diff --git a/config b/config index 7de5cc81d..1ca41bb28 160000 --- a/config +++ b/config @@ -1 +1 @@ -Subproject commit 7de5cc81d6bd87d9b9651b416f5dfa0ef28eadf4 +Subproject commit 1ca41bb28a67bf7e09e9765ac60c967f2d4db506 diff --git a/pom.xml b/pom.xml index d9c743a99..0db949f04 100644 --- a/pom.xml +++ b/pom.xml @@ -74,11 +74,6 @@ gs-cloud-starter-webmvc ${project.version} - - org.geoserver.cloud - gs-cloud-starter-reactive - ${project.version} - org.geoserver.cloud gs-cloud-starter-wms-extensions @@ -109,16 +104,6 @@ gs-cloud-catalog-cache ${project.version} - - org.geoserver.cloud.catalog.service - gs-cloud-reactive-catalog-client - ${project.version} - - - org.geoserver.cloud.catalog.service - gs-cloud-reactive-catalog-server - ${revision} - org.geoserver.cloud.catalog.backend gs-cloud-catalog-backend-common @@ -134,11 +119,6 @@ gs-cloud-catalog-backend-jdbcconfig ${project.version} - - org.geoserver.cloud.catalog.backend - gs-cloud-catalog-backend-catalog-service - ${project.version} - org.geoserver.cloud.catalog.backend gs-cloud-catalog-backend-pgsql diff --git a/src/apps/geoserver/catalog/Dockerfile b/src/apps/geoserver/catalog/Dockerfile deleted file mode 100644 index 4574b0981..000000000 --- a/src/apps/geoserver/catalog/Dockerfile +++ /dev/null @@ -1,55 +0,0 @@ -FROM eclipse-temurin:17-jre as builder -ARG JAR_FILE=target/gs-cloud-*-bin.jar - -RUN apt update && \ -apt install -y fonts-deva \ -fonts-font-awesome \ -fonts-freefont-ttf \ -fonts-material-design-icons-iconfont \ -fonts-materialdesignicons-webfont \ -fonts-roboto - -COPY ${JAR_FILE} application.jar - -RUN java -Djarmode=layertools -jar application.jar extract - -########## -FROM eclipse-temurin:17-jre -COPY target/config/ /etc/gscloud/ - -LABEL maintainer="GeoServer PSC " - -COPY --from=builder /usr/share/fonts/truetype/* /usr/share/fonts/truetype/ - -RUN mkdir -p /opt/app/bin -RUN mkdir -p /opt/app/data_directory && chmod 0777 /opt/app/data_directory -VOLUME /opt/app/data_directory - -WORKDIR /opt/app/bin -ENV JAVA_TOOL_OPTS="\ ---add-exports=java.desktop/sun.awt.image=ALL-UNNAMED \ ---add-opens=java.base/java.lang=ALL-UNNAMED \ ---add-opens=java.base/java.util=ALL-UNNAMED \ ---add-opens=java.base/java.lang.reflect=ALL-UNNAMED \ ---add-opens=java.base/java.text=ALL-UNNAMED \ ---add-opens=java.desktop/java.awt.font=ALL-UNNAMED \ ---add-opens=java.desktop/sun.awt.image=ALL-UNNAMED \ ---add-opens=java.naming/com.sun.jndi.ldap=ALL-UNNAMED \ --Djava.awt.headless=true" -ENV JAVA_OPTS= -EXPOSE 8080 -EXPOSE 8081 - -COPY --from=builder dependencies/ ./ -COPY --from=builder snapshot-dependencies/ ./ -COPY --from=builder spring-boot-loader/ ./ -COPY --from=builder application/ ./ - -HEALTHCHECK \ ---interval=10s \ ---timeout=5s \ ---start-period=30s \ ---retries=5 \ -CMD curl -f -s -o /dev/null localhost:8081/actuator/health || exit 1 - -CMD exec env USER_ID="$(id -u)" USER_GID="$(id -g)" java $JAVA_OPTS $JAVA_TOOL_OPTS org.springframework.boot.loader.JarLauncher diff --git a/src/apps/geoserver/catalog/README.md b/src/apps/geoserver/catalog/README.md deleted file mode 100644 index 6d821a9ee..000000000 --- a/src/apps/geoserver/catalog/README.md +++ /dev/null @@ -1,7 +0,0 @@ -# Cloud Native GeoServer Catalog service - -Spring Webflux reactive microservice that exposes the GeoServer *catalog*, *global*, and *resources* configuration -objects through a RESTful API to other microservices, in order to abstract out the microservices that require access -to the catalog from the actual catalog backend and implementation. - -Follow the service [documentation](../../../docs/develop/services/catalog-service.md) and keep it up to date . diff --git a/src/apps/geoserver/catalog/pom.xml b/src/apps/geoserver/catalog/pom.xml deleted file mode 100644 index 1eb29ed32..000000000 --- a/src/apps/geoserver/catalog/pom.xml +++ /dev/null @@ -1,80 +0,0 @@ - - - 4.0.0 - - org.geoserver.cloud.apps - gs-cloud-services - ${revision} - - gs-cloud-catalog-service - jar - catalog-service - - false - geoserver-cloud-catalog - org.geoserver.cloud.catalog.app.CatalogServiceApplication - - - - org.geoserver.cloud - gs-cloud-starter-reactive - - - org.geoserver.cloud.catalog.service - gs-cloud-reactive-catalog-server - - - org.geoserver.cloud.catalog - gs-cloud-catalog-plugin - ${project.version} - test-jar - test - - - - - - maven-resources-plugin - 3.3.1 - - - copy-resources - - validate - - copy-resources - - - ${basedir}/target/config - - - ${maven.multiModuleProjectDirectory}/config/ - false - - - - - - - - - - - docker - - false - - docker - - - - - - com.spotify - dockerfile-maven-plugin - - - - - - diff --git a/src/apps/geoserver/catalog/src/main/java/org/geoserver/cloud/catalog/app/CatalogServiceApplication.java b/src/apps/geoserver/catalog/src/main/java/org/geoserver/cloud/catalog/app/CatalogServiceApplication.java deleted file mode 100644 index 41d74e9a4..000000000 --- a/src/apps/geoserver/catalog/src/main/java/org/geoserver/cloud/catalog/app/CatalogServiceApplication.java +++ /dev/null @@ -1,20 +0,0 @@ -/* - * (c) 2020 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.cloud.catalog.app; - -import org.springframework.boot.SpringApplication; -import org.springframework.boot.autoconfigure.SpringBootApplication; - -@SpringBootApplication -public class CatalogServiceApplication { - - public static void main(String[] args) { - try { - SpringApplication.run(CatalogServiceApplication.class, args); - } catch (RuntimeException e) { - System.exit(-1); - } - } -} diff --git a/src/apps/geoserver/catalog/src/main/resources/bootstrap.yml b/src/apps/geoserver/catalog/src/main/resources/bootstrap.yml deleted file mode 100644 index 9ee53e9c4..000000000 --- a/src/apps/geoserver/catalog/src/main/resources/bootstrap.yml +++ /dev/null @@ -1,71 +0,0 @@ -info: - component: Catalog and Config Server - instance-id: ${spring.application.name}:${vcap.application.instance_id:${spring.application.instance_id:${spring.cloud.client.ip-address}}:${server.port}} - -geoserver: - security.enabled: false - catalog: - # Disable isolated catalog, it checks the org.geoserver.ows.Dispatcher.REQUEST to check if an OWS is in progress, - # which can never be the case, and causes a java.lang.NoClassDefFoundError on org.springframework.web.servlet.mvc.AbstractController - isolated: false - # Disable advertised catalog, it checks the org.geoserver.ows.Dispatcher.REQUEST to check if an OWS is in progress, - # which can never be the case, and causes a java.lang.NoClassDefFoundError on org.springframework.web.servlet.mvc.AbstractController - advertised: false - # Disable LocalWorkspaceCatalog decorator, this service exposes a "raw catalog" backend, there's no concept of local workspaces - localWorkspace: false - secure: false - catalog-service: - io-threads: - # if using jdbcconfig, make io-size be about half the size of geoserver.backend.jdbcconfig.datasource.maximumPoolSize, - # it has the tendency to use more than one jdbc connection for some requests - max-size: 8 - max-queued: 10000 - bus: - send-events: false - receive-events: true - send-object: false - send-diff: false -server: - port: 8080 - # one of never, always, on_trace_param (deprecated), on_param - error.include-stacktrace: on-param -management.server.port: 8081 -spring: - config: - import: -# import definition of common bootstrap configuration profiles - - classpath:gs_cloud_bootstrap_profiles.yml -# load externalized configuration from geoserver.yml - name: geoserver -# and always include the service specific settings from the profile - profiles.include: catalog_service -# also ask for geoserver.yml when loading the externalized config through a config-server - cloud.config.name: geoserver - main: - banner-mode: off - allow-bean-definition-overriding: true - allow-circular-references: true # false by default since spring-boot 2.6.0, breaks geoserver initialization - web-application-type: reactive - application: - name: catalog-service - jackson: - default-property-inclusion: non-empty - serialization: - indent-output: false - autoconfigure: - exclude: - - org.springframework.boot.autoconfigure.security.reactive.ReactiveSecurityAutoConfiguration - - org.springframework.boot.autoconfigure.security.reactive.ReactiveUserDetailsServiceAutoConfiguration - - org.springframework.boot.actuate.autoconfigure.security.reactive.ReactiveManagementWebSecurityAutoConfiguration - -# override default of true, this service does not use the registry (when eureka client is enabled) -eureka.client.fetch-registry: false - -logging: - level: - org.springframework.retry: debug ---- -# local profile, used for development only. Other settings like config and eureka urls in gs_cloud_bootstrap_profiles.yml -spring.config.activate.on-profile: local -server.port: 9100 -management.server.port: 8100 diff --git a/src/apps/geoserver/pom.xml b/src/apps/geoserver/pom.xml index 4a701fa11..4729ee95d 100644 --- a/src/apps/geoserver/pom.xml +++ b/src/apps/geoserver/pom.xml @@ -17,8 +17,6 @@ restconfig webui gwc - - diff --git a/src/catalog/README.md b/src/catalog/README.md index 7bc08aa78..4ec02a2fd 100644 --- a/src/catalog/README.md +++ b/src/catalog/README.md @@ -7,14 +7,14 @@ Dependency graph: ^ | (catalog-event-bus) <-------- (catalog-backend-starter) ------> (catalog-cache) - ^ | \ + / | \ / | \--> [gs-jdbcconfig] / | \ / | \--> ... / | - / +--> (catalog-service-client) + / +--> (pgconfig) / - (catalog-service) + (data-directory) ``` ## pluggable-catalog-support @@ -28,12 +28,14 @@ Implements `spring-could-bus` based event notification of catalog and configurat ## catalog-backend-starter -Provides spring atuo-configuration for several catalog back-ends. Namely: traditional file based data directory, jdbcconfig, and catalog-service-client. More can be added as implementations are developed. +Provides spring atuo-configuration for several catalog back-ends. Namely: traditional file based data directory, jdbcconfig, and pgconfig. More can be added as implementations are developed. depends on: - * catalog-event-bus - * gs-jdbcconfig - * catalog-service-client + * gs-cloud-catalog-events + * gs-cloud-catalog-cache + * gs-cloud-catalog-backend-datadir + * gs-cloud-catalog-backend-jdbcconfig + * gs-cloud-catalog-backend-pgsql ## catalog-cache @@ -42,18 +44,6 @@ Based on `spring-boot-starter-cache`, decorates the application catalog's backen depends on: * catalog-event-bus -## catalog-service-client - -Catalog implementation to use `catalog-service` as the application's catalog backend. Hooks into the configured `Catalog` and `ResourceStore` - -## catalog-service - -Microservice that implements the web-api to back the `catalog-service-client`. - - depends on: - * catalog-backend-starter (hence transitively on all the supported backends) - - # Common configuration properties The following configuration properties apply to all *GeoServer* microservices (i.e. not edge services): diff --git a/src/catalog/backends/catalog-service/pom.xml b/src/catalog/backends/catalog-service/pom.xml deleted file mode 100644 index 129928d33..000000000 --- a/src/catalog/backends/catalog-service/pom.xml +++ /dev/null @@ -1,54 +0,0 @@ - - - 4.0.0 - - org.geoserver.cloud.catalog.backend - gs-cloud-catalog-backends - ${revision} - - gs-cloud-catalog-backend-catalog-service - jar - Autoconfigurations for using the reactive catalog service as Catalog and config backend - - - org.geoserver.cloud.catalog.backend - gs-cloud-catalog-backend-common - - - org.geoserver.cloud.catalog.service - gs-cloud-reactive-catalog-client - - - org.geoserver.cloud.catalog - gs-cloud-catalog-events - true - - - org.springframework.boot - spring-boot-starter-actuator - true - - - org.springframework.boot - spring-boot-configuration-processor - true - - - - org.springframework - spring-webmvc - provided - - - - javax.servlet - javax.servlet-api - provided - - - org.springframework.boot - spring-boot-autoconfigure-processor - true - - - diff --git a/src/catalog/backends/catalog-service/src/main/java/org/geoserver/cloud/autoconfigure/catalog/backend/catalogservice/CatalogClientBackendAutoConfiguration.java b/src/catalog/backends/catalog-service/src/main/java/org/geoserver/cloud/autoconfigure/catalog/backend/catalogservice/CatalogClientBackendAutoConfiguration.java deleted file mode 100644 index 00c3631b5..000000000 --- a/src/catalog/backends/catalog-service/src/main/java/org/geoserver/cloud/autoconfigure/catalog/backend/catalogservice/CatalogClientBackendAutoConfiguration.java +++ /dev/null @@ -1,27 +0,0 @@ -/* - * (c) 2020 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.cloud.autoconfigure.catalog.backend.catalogservice; - -import org.geoserver.cloud.autoconfigure.catalog.backend.core.DefaultUpdateSequenceAutoConfiguration; -import org.geoserver.cloud.config.catalog.backend.catalogservice.CatalogClientBackendConfigurer; -import org.geoserver.cloud.config.catalog.backend.core.GeoServerBackendConfigurer; -import org.springframework.boot.autoconfigure.AutoConfiguration; -import org.springframework.boot.autoconfigure.EnableAutoConfiguration; -import org.springframework.context.annotation.Import; - -/** - * {@link EnableAutoConfiguration @EnableAutoConfiguration} auto-configuration to use the {@code - * catalog-service} microservice as the {@link GeoServerBackendConfigurer catalog and configuration - * backend} through the {@link CatalogClientBackendConfigurer} - * - *

Engages if enabled and configured as described by the {@link CatalogService} configuration - * properties under the {@code geoserver.backend.catalog-service} prefix. - * - * @see ConditionalOnCatalogServiceClientEnabled - */ -@AutoConfiguration(before = DefaultUpdateSequenceAutoConfiguration.class) -@ConditionalOnCatalogServiceClientEnabled -@Import(CatalogClientBackendConfigurer.class) -public class CatalogClientBackendAutoConfiguration {} diff --git a/src/catalog/backends/catalog-service/src/main/java/org/geoserver/cloud/autoconfigure/catalog/backend/catalogservice/ConditionalOnCatalogServiceClientEnabled.java b/src/catalog/backends/catalog-service/src/main/java/org/geoserver/cloud/autoconfigure/catalog/backend/catalogservice/ConditionalOnCatalogServiceClientEnabled.java deleted file mode 100644 index b493f787b..000000000 --- a/src/catalog/backends/catalog-service/src/main/java/org/geoserver/cloud/autoconfigure/catalog/backend/catalogservice/ConditionalOnCatalogServiceClientEnabled.java +++ /dev/null @@ -1,25 +0,0 @@ -/* - * (c) 2020 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.cloud.autoconfigure.catalog.backend.catalogservice; - -import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; -import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; - -import java.lang.annotation.Documented; -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -@Retention(RetentionPolicy.RUNTIME) -@Target({ElementType.METHOD, ElementType.TYPE}) -@Documented -@ConditionalOnClass(org.geoserver.cloud.catalog.client.impl.CatalogClientConfiguration.class) -@ConditionalOnProperty( - prefix = "geoserver.backend.catalog-service", - name = "enabled", - havingValue = "true", - matchIfMissing = false) -public @interface ConditionalOnCatalogServiceClientEnabled {} diff --git a/src/catalog/backends/catalog-service/src/main/java/org/geoserver/cloud/config/catalog/backend/catalogservice/CatalogClientBackendConfigurer.java b/src/catalog/backends/catalog-service/src/main/java/org/geoserver/cloud/config/catalog/backend/catalogservice/CatalogClientBackendConfigurer.java deleted file mode 100644 index 3838a0876..000000000 --- a/src/catalog/backends/catalog-service/src/main/java/org/geoserver/cloud/config/catalog/backend/catalogservice/CatalogClientBackendConfigurer.java +++ /dev/null @@ -1,108 +0,0 @@ -/* - * (c) 2020 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.cloud.config.catalog.backend.catalogservice; - -import lombok.extern.slf4j.Slf4j; - -import org.geoserver.GeoServerConfigurationLock; -import org.geoserver.catalog.plugin.ExtendedCatalogFacade; -import org.geoserver.cloud.catalog.client.impl.CatalogClientCatalogFacade; -import org.geoserver.cloud.catalog.client.impl.CatalogClientConfiguration; -import org.geoserver.cloud.catalog.client.impl.CatalogClientGeoServerFacade; -import org.geoserver.cloud.catalog.client.impl.CatalogClientResourceStore; -import org.geoserver.cloud.config.catalog.backend.core.GeoServerBackendConfigurer; -import org.geoserver.config.GeoServerFacade; -import org.geoserver.config.GeoServerLoader; -import org.geoserver.platform.GeoServerResourceLoader; -import org.geoserver.platform.config.UpdateSequence; -import org.geoserver.platform.resource.FileSystemResourceStore; -import org.geoserver.platform.resource.ResourceStore; -import org.springframework.beans.factory.annotation.Autowired; -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.annotation.Import; -import org.springframework.core.env.Environment; - -import java.io.File; - -@Configuration(proxyBeanMethods = true) -@EnableConfigurationProperties(CatalogClientProperties.class) -@Import(CatalogClientConfiguration.class) -@Slf4j(topic = "org.geoserver.cloud.config.catalogclient") -public class CatalogClientBackendConfigurer extends GeoServerBackendConfigurer { - - private @Autowired CatalogClientCatalogFacade catalogClientFacade; - private @Autowired CatalogClientGeoServerFacade configClientFacade; - private @Autowired CatalogClientResourceStore catalogServiceResourceStore; - - private @Autowired CatalogClientProperties catalogClientConfig; - - public CatalogClientBackendConfigurer() { - log.info( - "Loading geoserver config backend with {}", - CatalogClientBackendConfigurer.class.getSimpleName()); - } - - protected @Bean @Override UpdateSequence updateSequence() { - throw new UnsupportedOperationException("implement"); - } - - protected @Bean @Override GeoServerConfigurationLock configurationLock() { - throw new UnsupportedOperationException("implement"); - } - - protected @Bean @Override ExtendedCatalogFacade catalogFacade() { - return catalogClientFacade; - } - - protected @Bean @Override GeoServerFacade geoserverFacade() { - return configClientFacade; - } - - @Bean(name = {"resourceStoreImpl"}) - protected @Override CatalogClientResourceStore resourceStoreImpl() { - CatalogClientResourceStore store = catalogServiceResourceStore; - File cacheDirectory = catalogClientConfig.getCacheDirectory(); - if (null != cacheDirectory) { - store.setLocalCacheDirectory(cacheDirectory); - } - return store; - } - - @DependsOn({ - "extensions", - "wmsLoader", - "wfsLoader", - "wcsLoader", - "wpsServiceLoader", - "wmtsLoader" - }) - protected @Bean @Override GeoServerLoader geoServerLoaderImpl() { - return new CatalogClientGeoServerLoader(resourceLoader()); - } - - protected @Bean @Override GeoServerResourceLoader resourceLoader() { - CatalogClientResourceStore resourceStore = resourceStoreImpl(); - GeoServerResourceLoader resourceLoader = new GeoServerResourceLoader(resourceStore); - File cacheDirectory = catalogClientConfig.getCacheDirectory(); - if (null != cacheDirectory) { - resourceLoader.setBaseDirectory(cacheDirectory); - } - return resourceLoader; - } - - @Bean - ResourceStore catalogServiceFallbackResourceStore(@Autowired Environment springEnv) { - File dir = - springEnv.getProperty( - "geoserver.backend.catalog-service.fallback-resource-directory", - File.class); - if (dir == null) return null; - dir.mkdirs(); - return new FileSystemResourceStore(dir); - } -} diff --git a/src/catalog/backends/catalog-service/src/main/java/org/geoserver/cloud/config/catalog/backend/catalogservice/CatalogClientGeoServerLoader.java b/src/catalog/backends/catalog-service/src/main/java/org/geoserver/cloud/config/catalog/backend/catalogservice/CatalogClientGeoServerLoader.java deleted file mode 100644 index f08969ea0..000000000 --- a/src/catalog/backends/catalog-service/src/main/java/org/geoserver/cloud/config/catalog/backend/catalogservice/CatalogClientGeoServerLoader.java +++ /dev/null @@ -1,66 +0,0 @@ -/* - * (c) 2020 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.cloud.config.catalog.backend.catalogservice; - -import lombok.extern.slf4j.Slf4j; - -import org.geoserver.catalog.Catalog; -import org.geoserver.catalog.WorkspaceInfo; -import org.geoserver.config.GeoServer; -import org.geoserver.config.GeoServerInfo; -import org.geoserver.config.GeoServerLoader; -import org.geoserver.config.util.XStreamPersister; -import org.geoserver.platform.GeoServerResourceLoader; -import org.geotools.api.filter.Filter; - -import java.io.IOException; - -/** */ -@Slf4j -public class CatalogClientGeoServerLoader extends GeoServerLoader { - - public CatalogClientGeoServerLoader(GeoServerResourceLoader resourceLoader) { - super(resourceLoader); - } - - protected @Override void initializeDefaultStyles(Catalog catalog) throws IOException { - try { - super.initializeDefaultStyles(catalog); - } catch (Exception e) { - log.warn( - "Unable to connect to catalog-service's catalog API during GeoServerLoader bean initialization", - e); - } - } - - protected @Override void loadCatalog(Catalog catalog, XStreamPersister xp) throws Exception { - log.info("Checking catalog service health..."); - try { - int count = catalog.count(WorkspaceInfo.class, Filter.INCLUDE); - log.info( - "Catalog-service reports {} workspaces, roundtrip succeeded, assuming service is healthy", - count); - } catch (Exception e) { - log.warn( - "Unable to connect to catalog-service's catalog API during GeoServerLoader bean initialization", - e); - } - } - - protected @Override void loadGeoServer(GeoServer geoServer, XStreamPersister xp) - throws Exception { - log.info("Checking config service health..."); - try { - GeoServerInfo global = geoServer.getGlobal(); - log.info( - "Catalog-service returned global config, update sequence: {}, roundtrip succeeded, assuming service is healthy", - global.getUpdateSequence()); - } catch (Exception e) { - log.warn( - "Unable to connect to catalog-service's config API during GeoServerLoader bean initialization", - e); - } - } -} diff --git a/src/catalog/backends/catalog-service/src/main/java/org/geoserver/cloud/config/catalog/backend/catalogservice/CatalogClientProperties.java b/src/catalog/backends/catalog-service/src/main/java/org/geoserver/cloud/config/catalog/backend/catalogservice/CatalogClientProperties.java deleted file mode 100644 index 5d0950499..000000000 --- a/src/catalog/backends/catalog-service/src/main/java/org/geoserver/cloud/config/catalog/backend/catalogservice/CatalogClientProperties.java +++ /dev/null @@ -1,24 +0,0 @@ -/* - * (c) 2020 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.cloud.config.catalog.backend.catalogservice; - -import lombok.Data; -import lombok.Generated; - -import org.springframework.boot.context.properties.ConfigurationProperties; - -import java.io.File; - -/** - * Configuration properties bean to use the {@code catalog-service} micro-service client back-end - * and can be used as a {@link ConfigurationProperties @ConfigurationProperties} - */ -@Generated -@ConfigurationProperties(prefix = "geoserver.backend.catalog-service") -public @Data class CatalogClientProperties { - private boolean enabled; - private String url; - private File cacheDirectory; -} diff --git a/src/catalog/backends/catalog-service/src/main/resources/META-INF/spring.factories b/src/catalog/backends/catalog-service/src/main/resources/META-INF/spring.factories deleted file mode 100644 index fb7b52f42..000000000 --- a/src/catalog/backends/catalog-service/src/main/resources/META-INF/spring.factories +++ /dev/null @@ -1,3 +0,0 @@ -# Auto Configure -org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ -org.geoserver.cloud.autoconfigure.catalog.backend.catalogservice.CatalogClientBackendAutoConfiguration \ No newline at end of file diff --git a/src/catalog/backends/catalog-service/src/test/java/org/geoserver/cloud/autoconfigure/catalog/backend/catalogservice/CatalogClientBackendAutoConfigurationTest.java b/src/catalog/backends/catalog-service/src/test/java/org/geoserver/cloud/autoconfigure/catalog/backend/catalogservice/CatalogClientBackendAutoConfigurationTest.java deleted file mode 100644 index f3f276f1a..000000000 --- a/src/catalog/backends/catalog-service/src/test/java/org/geoserver/cloud/autoconfigure/catalog/backend/catalogservice/CatalogClientBackendAutoConfigurationTest.java +++ /dev/null @@ -1,113 +0,0 @@ -/* - * (c) 2020 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.cloud.autoconfigure.catalog.backend.catalogservice; - -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.instanceOf; -import static org.junit.jupiter.api.Assertions.assertSame; - -import org.geoserver.catalog.CatalogFacade; -import org.geoserver.catalog.plugin.CatalogPlugin; -import org.geoserver.cloud.autoconfigure.catalog.backend.core.GeoServerBackendAutoConfiguration; -import org.geoserver.cloud.autoconfigure.security.GeoServerSecurityAutoConfiguration; -import org.geoserver.cloud.catalog.client.impl.CatalogClientCatalogFacade; -import org.geoserver.cloud.catalog.client.impl.CatalogClientGeoServerFacade; -import org.geoserver.cloud.catalog.client.impl.CatalogClientResourceStore; -import org.geoserver.cloud.config.catalog.backend.catalogservice.CatalogClientBackendConfigurer; -import org.geoserver.cloud.config.catalog.backend.catalogservice.CatalogClientGeoServerLoader; -import org.geoserver.platform.GeoServerResourceLoader; -import org.junit.jupiter.api.Disabled; -import org.junit.jupiter.api.Test; -import org.springframework.boot.autoconfigure.AutoConfigurations; -import org.springframework.boot.autoconfigure.cache.CacheAutoConfiguration; -import org.springframework.boot.autoconfigure.web.reactive.function.client.WebClientAutoConfiguration; -import org.springframework.boot.test.context.runner.ApplicationContextRunner; - -import reactivefeign.spring.config.ReactiveFeignAutoConfiguration; - -/** - * Test {@link CatalogClientBackendConfigurer} through {@link CatalogClientBackendAutoConfiguration} - * when {@code geoserver.backend.catalog-service.enabled=true} - */ -@Disabled("Make it run without ReactiveCatalogClient trying to connect") -class CatalogClientBackendAutoConfigurationTest { - - // geoserver.security.enabled=false to avoid calling the catalog during bean initialization, - // since there's no backend service to connect to - private final ApplicationContextRunner contextRunner = - new ApplicationContextRunner() - .withAllowBeanDefinitionOverriding(true) - .withPropertyValues( - "reactive.feign.loadbalancer.enabled=false", - "geoserver.backend.catalog-service.enabled=true", - "geoserver.security.enabled=false") - .withAllowBeanDefinitionOverriding(true) - .withConfiguration( - AutoConfigurations.of( // - GeoServerBackendAutoConfiguration.class, - GeoServerSecurityAutoConfiguration.class, - ReactiveFeignAutoConfiguration.class, - WebClientAutoConfiguration.class, - CacheAutoConfiguration.class)); - - @Test - void testCatalog() { - contextRunner.run( - context -> - context.isTypeMatch( - "rawCatalog", org.geoserver.catalog.plugin.CatalogPlugin.class)); - } - - @Test - void testCatalogFacade() { - contextRunner.run( - context -> context.isTypeMatch("catalogFacade", CatalogClientCatalogFacade.class)); - } - - @Test - void testCatalogFacadeIsRawCatalogFacade() { - contextRunner.run( - context -> { - CatalogPlugin catalog = context.getBean("rawCatalog", CatalogPlugin.class); - CatalogFacade rawCatalogFacade = - context.getBean("catalogFacade", CatalogFacade.class); - assertSame(rawCatalogFacade, catalog.getRawFacade()); - }); - } - - @Test - void testResourceStore() { - contextRunner.run( - context -> - context.isTypeMatch("resourceStoreImpl", CatalogClientResourceStore.class)); - } - - @Test - void testResourceLoadersResourceStore() { - contextRunner.run( - context -> { - GeoServerResourceLoader resourceLoader = - context.getBean(GeoServerResourceLoader.class); - assertThat( - resourceLoader.getResourceStore(), - instanceOf(CatalogClientResourceStore.class)); - }); - } - - @Test - void testGeoserverFacade() { - contextRunner.run( - context -> - context.isTypeMatch("geoserverFacade", CatalogClientGeoServerFacade.class)); - } - - @Test - void testGeoserverLoader() { - contextRunner.run( - context -> - context.isTypeMatch( - "geoServerLoaderImpl", CatalogClientGeoServerLoader.class)); - } -} diff --git a/src/catalog/backends/catalog-service/src/test/resources/application.yml b/src/catalog/backends/catalog-service/src/test/resources/application.yml deleted file mode 100644 index ad138e97f..000000000 --- a/src/catalog/backends/catalog-service/src/test/resources/application.yml +++ /dev/null @@ -1,33 +0,0 @@ -info: - instance-id: test-instance-id -spring: - main: - banner-mode: off - allow-bean-definition-overriding: true - # false by default since spring-boot 2.6.0, breaks geoserver initialization - allow-circular-references: true - cloud.bus.enabled: false - autoconfigure: - exclude: - - org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration - - -eureka.client.enabled: false - -geoserver: - backend: - catalog-service: - enabled: false - url: catalog-service -# resource-store.fallback.enabled: ${java.io.tmpdir}/gs_cloud/catalog_client_resource_store_fallback -# resource-store.fallback: ${java.io.tmpdir}/gs_cloud/catalog_client_resource_store_fallback - -logging: - level: - root: WARN - #org.geoserver.platform: ERROR - org.geoserver: warn - org.geoserver.cloud: warn - org.geoserver.cloud.config.factory: warn - org.geoserver.jdbcconfig: warn - org.geoserver.jdbcstore: warn diff --git a/src/catalog/backends/catalog-service/src/test/resources/logback-test.xml b/src/catalog/backends/catalog-service/src/test/resources/logback-test.xml deleted file mode 100644 index 92a70edd5..000000000 --- a/src/catalog/backends/catalog-service/src/test/resources/logback-test.xml +++ /dev/null @@ -1,15 +0,0 @@ - - - - %d{HH:mm:ss.SSS} [%thread] %-5level %logger - %msg%n - - - - - - - - - - - \ No newline at end of file diff --git a/src/catalog/backends/pom.xml b/src/catalog/backends/pom.xml index 6f995cf87..43356b389 100644 --- a/src/catalog/backends/pom.xml +++ b/src/catalog/backends/pom.xml @@ -41,15 +41,4 @@ test - - - catalog-service - - false - - - catalog-service - - - diff --git a/src/catalog/catalog-server/client/README.md b/src/catalog/catalog-server/client/README.md deleted file mode 100644 index cf96361e8..000000000 --- a/src/catalog/catalog-server/client/README.md +++ /dev/null @@ -1,6 +0,0 @@ -# GeoServer Catalog micro-service client - -Client library for the catalog-microservice. - -The `catalog-service` client uses [String Cloud OpenFeign](https://cloud.spring.io/spring-cloud-openfeign/reference/html/) - diff --git a/src/catalog/catalog-server/client/pom.xml b/src/catalog/catalog-server/client/pom.xml deleted file mode 100644 index fd15ee75d..000000000 --- a/src/catalog/catalog-server/client/pom.xml +++ /dev/null @@ -1,63 +0,0 @@ - - - 4.0.0 - - org.geoserver.cloud.catalog.service - gs-cloud-catalog-server - ${revision} - - gs-cloud-reactive-catalog-client - jar - Reactive catalog-service client library - - - org.springframework.boot - spring-boot-starter-json - - - org.geoserver.cloud.catalog.jackson - gs-cloud-starter-jackson - - - org.geoserver.cloud.catalog - gs-cloud-catalog-plugin - - - org.geoserver - gs-main - - - org.springframework.cloud - spring-cloud-starter-netflix-eureka-client - - - com.playtika.reactivefeign - feign-reactor-webclient - - - com.playtika.reactivefeign - feign-reactor-cloud - - - com.playtika.reactivefeign - feign-reactor-spring-configuration - - - io.github.openfeign - feign-slf4j - - - - org.geoserver.cloud.catalog - gs-cloud-catalog-plugin - ${project.version} - test-jar - test - - - org.springframework.boot - spring-boot-starter-web - test - - - diff --git a/src/catalog/catalog-server/client/src/main/java/org/geoserver/cloud/catalog/client/impl/CatalogClientCatalogFacade.java b/src/catalog/catalog-server/client/src/main/java/org/geoserver/cloud/catalog/client/impl/CatalogClientCatalogFacade.java deleted file mode 100644 index 518401928..000000000 --- a/src/catalog/catalog-server/client/src/main/java/org/geoserver/cloud/catalog/client/impl/CatalogClientCatalogFacade.java +++ /dev/null @@ -1,135 +0,0 @@ -/* - * (c) 2020 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.cloud.catalog.client.impl; - -import lombok.NonNull; - -import org.geoserver.catalog.Catalog; -import org.geoserver.catalog.CatalogFacade; -import org.geoserver.catalog.CatalogInfo; -import org.geoserver.catalog.LayerGroupInfo; -import org.geoserver.catalog.LayerInfo; -import org.geoserver.catalog.MapInfo; -import org.geoserver.catalog.NamespaceInfo; -import org.geoserver.catalog.ResourceInfo; -import org.geoserver.catalog.StoreInfo; -import org.geoserver.catalog.StyleInfo; -import org.geoserver.catalog.WorkspaceInfo; -import org.geoserver.catalog.impl.ModificationProxy; -import org.geoserver.catalog.impl.ResolvingProxy; -import org.geoserver.catalog.plugin.RepositoryCatalogFacade; -import org.geoserver.catalog.plugin.forwarding.ResolvingCatalogFacadeDecorator; -import org.geoserver.catalog.plugin.resolving.CatalogPropertyResolver; -import org.geoserver.catalog.plugin.resolving.CollectionPropertiesInitializer; -import org.geoserver.catalog.plugin.resolving.ResolvingProxyResolver; -import org.geoserver.cloud.catalog.client.repository.CatalogClientRepository; - -import java.lang.reflect.Proxy; -import java.util.function.Function; -import java.util.function.Supplier; - -/** - * {@link CatalogFacade} for {@code catalog-service}, being a {@link - * ResolvingCatalogFacadeDecorator}, wraps the raw {@link RepositoryCatalogFacade} that delegates to - * the {@link CatalogClientRepository catalog client repositories}, and adds the necessary {@link - * #setInboundResolver inbound} and {@link #setOutboundResolver outbound} resolvers to ensure valid - * input and output for the decorated facade. - * - *

Note these in/out bound resolvers do not deal with {@link ModificationProxy} at all. It - * is up to the {@link Catalog} implementation itself to do that if it so requires it. - * - *

This decorator specializes in resolving the objects returned by {@link ReactiveCatalogClient} - * through {@link CatalogClientRepository}. For instance: - * - *

- * - *

    - *
  • for in-bound objects, it checks no {@code java.lang.reflect.Proxy} instances get in, - * throwing an {@link IllegalArgumentException} if so happens, as it'd be a programming error, - * probably the catalog not unwrapping objects before deliering them down to the facade. - *
  • for out-bound objects: - *
      - *
    • Resolves {@link ResolvingProxy} proxied object references (see {@link - * ResolvingProxyResolver}); - *
    • then sets the {@link Catalog} property if the object so requires it (e.g. {@link - * StoreInfo#getCatalog()} (see {@link CatalogPropertyResolver}); - *
    • and finally resolves {@code null} collection properties to empty collections (see - * {@link CollectionPropertiesInitializer}) - *
    - *
- */ -public class CatalogClientCatalogFacade extends ResolvingCatalogFacadeDecorator { - - public CatalogClientCatalogFacade(@NonNull RepositoryCatalogFacade rawFacade) { - super(rawFacade); - } - - // set up resolving chain - @Override - public void setCatalog(Catalog catalog) { - super.setCatalog(catalog); - - final ResolvingProxyResolver proxyResolver = - ResolvingProxyResolver.of(catalog, true); - final CatalogPropertyResolver catalogPropertyResolver = - CatalogPropertyResolver.of(catalog); - final CollectionPropertiesInitializer collectionInitializer = - CollectionPropertiesInitializer.instance(); - - // resolver for single-object returning methods - Function outboundResolver = - proxyResolver.andThen(catalogPropertyResolver).andThen(collectionInitializer); - - // resolver supplier for Stream<> returning methods, uses memoized proxy resolver that - // caches resolved references for the lifetime of the stream - Supplier> streamResolver = // - () -> - proxyResolver - .memoizing() // - .andThen(catalogPropertyResolver) // - .andThen(collectionInitializer); - - setInboundResolver( - o -> { - if (o instanceof Proxy) { - throw new IllegalArgumentException( - "This CatalogFacade does not accept java.lang.reflect.Proxy instances: " - + o); - } - return o; - }); - - setInnerResolver(repo(WorkspaceInfo.class), cast(outboundResolver), streamResolver); - setInnerResolver(repo(NamespaceInfo.class), cast(outboundResolver), streamResolver); - setInnerResolver(repo(StoreInfo.class), cast(outboundResolver), streamResolver); - setInnerResolver(repo(ResourceInfo.class), cast(outboundResolver), streamResolver); - setInnerResolver(repo(LayerInfo.class), cast(outboundResolver), streamResolver); - setInnerResolver(repo(LayerGroupInfo.class), cast(outboundResolver), streamResolver); - setInnerResolver(repo(StyleInfo.class), cast(outboundResolver), streamResolver); - setInnerResolver(repo(MapInfo.class), cast(outboundResolver), streamResolver); - } - - @SuppressWarnings("unchecked") - private Function cast(Function f) { - return (Function) f; - } - - private CatalogClientRepository repo(Class type) { - return facade().repository(type); - } - - private void setInnerResolver( // - CatalogClientRepository catalogClientRepository, // - Function objectResolver, // - Supplier> memoizingResolver) { - - catalogClientRepository.setObjectResolver(objectResolver); - catalogClientRepository.setStreamResolver(memoizingResolver); - } - - protected @Override RepositoryCatalogFacade facade() { - return (RepositoryCatalogFacade) facade; - } -} diff --git a/src/catalog/catalog-server/client/src/main/java/org/geoserver/cloud/catalog/client/impl/CatalogClientConfiguration.java b/src/catalog/catalog-server/client/src/main/java/org/geoserver/cloud/catalog/client/impl/CatalogClientConfiguration.java deleted file mode 100644 index 4471e57cf..000000000 --- a/src/catalog/catalog-server/client/src/main/java/org/geoserver/cloud/catalog/client/impl/CatalogClientConfiguration.java +++ /dev/null @@ -1,93 +0,0 @@ -/* - * (c) 2020 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.cloud.catalog.client.impl; - -import org.geoserver.catalog.plugin.RepositoryCatalogFacade; -import org.geoserver.catalog.plugin.RepositoryCatalogFacadeImpl; -import org.geoserver.cloud.catalog.client.reactivefeign.BlockingResourceStoreClient; -import org.geoserver.cloud.catalog.client.reactivefeign.ReactiveConfigClient; -import org.geoserver.cloud.catalog.client.reactivefeign.ReactiveResourceStoreClient; -import org.geoserver.cloud.catalog.client.repository.CatalogClientConfigRepository; -import org.geoserver.cloud.catalog.client.repository.CatalogClientLayerGroupRepository; -import org.geoserver.cloud.catalog.client.repository.CatalogClientLayerRepository; -import org.geoserver.cloud.catalog.client.repository.CatalogClientMapRepository; -import org.geoserver.cloud.catalog.client.repository.CatalogClientNamespaceRepository; -import org.geoserver.cloud.catalog.client.repository.CatalogClientRepositoryConfiguration; -import org.geoserver.cloud.catalog.client.repository.CatalogClientResourceRepository; -import org.geoserver.cloud.catalog.client.repository.CatalogClientStoreRepository; -import org.geoserver.cloud.catalog.client.repository.CatalogClientStyleRepository; -import org.geoserver.cloud.catalog.client.repository.CatalogClientWorkspaceRepository; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.context.annotation.Import; - -@Configuration -@Import(CatalogClientRepositoryConfiguration.class) -public class CatalogClientConfiguration { - - private @Autowired CatalogClientWorkspaceRepository cloudWorkspaceRepository; - private @Autowired CatalogClientNamespaceRepository cloudNamespaceRepository; - private @Autowired CatalogClientStoreRepository cloudStoreRepository; - private @Autowired CatalogClientResourceRepository cloudResourceRepository; - private @Autowired CatalogClientLayerRepository cloudLayerRepository; - private @Autowired CatalogClientLayerGroupRepository cloudLayerGroupRepository; - private @Autowired CatalogClientStyleRepository cloudStyleRepository; - private @Autowired CatalogClientMapRepository cloudMapRepository; - - private @Autowired ReactiveConfigClient configClient; - private @Autowired ReactiveResourceStoreClient resourceStoreClient; - - @Bean - CatalogClientCatalogFacade rawCatalogServiceFacade() { - RepositoryCatalogFacade rawFacade = new RepositoryCatalogFacadeImpl(); - rawFacade.setWorkspaceRepository(cloudWorkspaceRepository); - rawFacade.setNamespaceRepository(cloudNamespaceRepository); - rawFacade.setStoreRepository(cloudStoreRepository); - rawFacade.setResourceRepository(cloudResourceRepository); - rawFacade.setLayerRepository(cloudLayerRepository); - rawFacade.setLayerGroupRepository(cloudLayerGroupRepository); - rawFacade.setStyleRepository(cloudStyleRepository); - rawFacade.setMapRepository(cloudMapRepository); - - CatalogClientCatalogFacade facade = new CatalogClientCatalogFacade(rawFacade); - return facade; - } - - @Bean - CatalogClientConfigRepository catalogServiceConfigRepository() { - return new CatalogClientConfigRepository(configClient); - } - - @Bean - CatalogClientGeoServerFacade catalogServiceGeoServerFacade() { - return new CatalogClientGeoServerFacade(catalogServiceConfigRepository()); - } - - @Bean - CatalogClientResourceStore catalogServiceResourceStore() { - BlockingResourceStoreClient blockingClient = - new BlockingResourceStoreClient(resourceStoreClient); - return new CatalogClientResourceStore(blockingClient); - } - - // @ConditionalOnProperty(name = "reactive.feign.jetty", havingValue = "true") - // @Bean JettyHttpClientFactory jettyHttpClientFactory() { - // return new JettyHttpClientFactory() { - // - // @Override - // public HttpClient build(boolean useHttp2) { - // HttpClient httpClient = new HttpClient(); - // try { - // httpClient.start(); - // } catch (Exception e) { - // e.printStackTrace(); - // throw new RuntimeException(e); - // } - // return httpClient; - // } - // }; - // } -} diff --git a/src/catalog/catalog-server/client/src/main/java/org/geoserver/cloud/catalog/client/impl/CatalogClientGeoServerFacade.java b/src/catalog/catalog-server/client/src/main/java/org/geoserver/cloud/catalog/client/impl/CatalogClientGeoServerFacade.java deleted file mode 100644 index 01bd08134..000000000 --- a/src/catalog/catalog-server/client/src/main/java/org/geoserver/cloud/catalog/client/impl/CatalogClientGeoServerFacade.java +++ /dev/null @@ -1,16 +0,0 @@ -/* - * (c) 2020 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.cloud.catalog.client.impl; - -import org.geoserver.cloud.catalog.client.repository.CatalogClientConfigRepository; -import org.geoserver.config.plugin.RepositoryGeoServerFacadeImpl; - -/** */ -public class CatalogClientGeoServerFacade extends RepositoryGeoServerFacadeImpl { - - public CatalogClientGeoServerFacade(CatalogClientConfigRepository repository) { - super(repository); - } -} diff --git a/src/catalog/catalog-server/client/src/main/java/org/geoserver/cloud/catalog/client/impl/CatalogClientResource.java b/src/catalog/catalog-server/client/src/main/java/org/geoserver/cloud/catalog/client/impl/CatalogClientResource.java deleted file mode 100644 index d9a01d624..000000000 --- a/src/catalog/catalog-server/client/src/main/java/org/geoserver/cloud/catalog/client/impl/CatalogClientResource.java +++ /dev/null @@ -1,193 +0,0 @@ -/* - * (c) 2020 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.cloud.catalog.client.impl; - -import com.google.common.io.ByteStreams; - -import lombok.AllArgsConstructor; -import lombok.NonNull; - -import org.geoserver.cloud.catalog.client.reactivefeign.ReactiveResourceStoreClient; -import org.geoserver.cloud.catalog.client.reactivefeign.ReactiveResourceStoreClient.ResourceDescriptor; -import org.geoserver.platform.resource.Resource; -import org.geoserver.platform.resource.ResourceListener; - -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.File; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.io.UncheckedIOException; -import java.nio.ByteBuffer; -import java.nio.file.Path; -import java.nio.file.Paths; -import java.util.List; -import java.util.Objects; - -/** */ -@AllArgsConstructor -class CatalogClientResource implements Resource { - - private @NonNull ReactiveResourceStoreClient.ResourceDescriptor descriptor; - private @NonNull CatalogClientResourceStore store; - - @Override - public String path() { - return descriptor.getPath(); - } - - @Override - public void addListener(ResourceListener listener) { - store.getResourceNotificationDispatcher().addListener(path(), listener); - } - - @Override - public void removeListener(ResourceListener listener) { - store.getResourceNotificationDispatcher().removeListener(path(), listener); - } - - @Override - public String name() { - return Paths.get(path()).getFileName().toString(); - } - - @Override - public Lock lock() { - return store.getLockProvider().acquire(path()); - } - - private byte[] toByteArray(org.springframework.core.io.Resource buff) { - try (InputStream in = buff.getInputStream()) { - byte[] array = ByteStreams.toByteArray(in); - return array; - } catch (IOException e) { - throw new UncheckedIOException(e); - } - } - - @Override - public byte[] getContents() throws IOException { - org.springframework.core.io.Resource contents = store.getFileContent(path()); - return toByteArray(contents); - } - - @Override - public void setContents(byte[] contents) throws IOException { - store.put(path(), ByteBuffer.wrap(contents)); - } - - @Override - public InputStream in() { - try { - return new ByteArrayInputStream(getContents()); - } catch (IOException e) { - throw new UncheckedIOException(e); - } - } - - @Override - public OutputStream out() { - return new ByteArrayOutputStream() { - @Override - public void close() throws IOException { - ByteBuffer buff = ByteBuffer.wrap(super.buf, 0, super.count); - store.put(path(), buff); - } - }; - } - - @Override - public File file() { - return store.file(this); - } - - @Override - public File dir() { - return store.dir(this); - } - - @Override - public long lastmodified() { - return descriptor.getLastModified(); - } - - @Override - public Resource parent() { - Path parentPath = Paths.get(path()).getParent(); - if (null == parentPath) { - parentPath = Paths.get(org.geoserver.platform.resource.Paths.BASE); // root - } - return store.get(parentPath.toString()); - } - - @Override - public Resource get(final String childName) { - Objects.requireNonNull(childName, "Resource path required"); - if ("".equals(childName)) { - return this; - } - Path path = Paths.get(path()); - Path child = path.resolve(childName); - return store.get(child.toString()); - } - - @Override - public List list() { - return store.list(path()).map(Resource.class::cast).toList(); - } - - @Override - public Type getType() { - return descriptor.getType(); - } - - @Override - public boolean delete() { - boolean removed = store.remove(path()); - if (removed) { - this.descriptor.setType(Type.UNDEFINED); - } - return removed; - } - - @Override - public boolean renameTo(Resource dest) { - boolean moved = store.move(path(), dest.path()); - if (moved) { - this.descriptor = store.get(dest.path()).getDescriptor(); - return true; - } - return moved; - } - - @NonNull - ResourceDescriptor getDescriptor() { - return this.descriptor; - } - - @Override - public String toString() { - return String.format( - "%s[path: %s, type: %s, lastModified: %s, lockProvider: %s]", - getClass().getSimpleName(), - descriptor.getPath(), - descriptor.getType(), - descriptor.getLastModified(), - store.getLockProvider().getClass().getSimpleName()); - } - - boolean isDirectory() { - return getType() == Type.DIRECTORY; - } - - boolean isFile() { - return getType() == Type.RESOURCE; - } - - boolean exists() { - return getType() != Type.UNDEFINED; - } -} diff --git a/src/catalog/catalog-server/client/src/main/java/org/geoserver/cloud/catalog/client/impl/CatalogClientResourceStore.java b/src/catalog/catalog-server/client/src/main/java/org/geoserver/cloud/catalog/client/impl/CatalogClientResourceStore.java deleted file mode 100644 index caefc98fd..000000000 --- a/src/catalog/catalog-server/client/src/main/java/org/geoserver/cloud/catalog/client/impl/CatalogClientResourceStore.java +++ /dev/null @@ -1,270 +0,0 @@ -/* - * (c) 2020 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.cloud.catalog.client.impl; - -import com.google.common.io.ByteStreams; - -import lombok.Getter; -import lombok.NonNull; -import lombok.Setter; -import lombok.extern.slf4j.Slf4j; - -import org.geoserver.cloud.catalog.client.reactivefeign.BlockingResourceStoreClient; -import org.geoserver.cloud.catalog.client.reactivefeign.ReactiveResourceStoreClient.ResourceDescriptor; -import org.geoserver.platform.resource.FileSystemResourceStore; -import org.geoserver.platform.resource.LockProvider; -import org.geoserver.platform.resource.MemoryLockProvider; -import org.geoserver.platform.resource.NullLockProvider; -import org.geoserver.platform.resource.Resource; -import org.geoserver.platform.resource.Resource.Lock; -import org.geoserver.platform.resource.Resource.Type; -import org.geoserver.platform.resource.ResourceListener; -import org.geoserver.platform.resource.ResourceNotification; -import org.geoserver.platform.resource.ResourceNotificationDispatcher; -import org.geoserver.platform.resource.ResourceStore; -import org.springframework.util.Assert; - -import java.io.File; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.io.UncheckedIOException; -import java.nio.ByteBuffer; -import java.nio.file.Files; -import java.nio.file.Path; -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; -import java.util.stream.Stream; - -/** */ -@Slf4j -public class CatalogClientResourceStore implements ResourceStore { - private static final NullLockProvider NULL_LOCK_PROVIDER = new NullLockProvider(); - - /** LockProvider used to secure resources for exclusive access */ - private @Getter @Setter @NonNull LockProvider lockProvider = NULL_LOCK_PROVIDER; - - private final BlockingResourceStoreClient remoteStore; - private FileSystemResourceStore localStore; - - /** - * No-op notification dispatcher, resources are live-through-the-wire. May end up needing a - * notification mechanism, but until proved differently, there seems to be no need for it. - */ - private ResourceNotificationDispatcher resourceNotificationDispatcher = - NullResourceNotificationDispatcher.INSTANCE; - - public CatalogClientResourceStore(@NonNull BlockingResourceStoreClient client) { - this.remoteStore = client; - Path localCache = getOrCreateDefaultLocalCacheDirectory(); - setLocalCacheDirectory(localCache.toFile()); - } - - protected Path getOrCreateDefaultLocalCacheDirectory() { - Path tmpdir = Path.of(System.getProperty("java.io.tmpdir")); - Path localCache = tmpdir.resolve("cngs/catalog-service/resource_store"); - if (!Files.isDirectory(localCache)) { - try { - Files.createDirectories(localCache); - } catch (IOException e) { - throw new IllegalStateException( - "Unable to create catalog-service local resource cache directory " - + localCache.toString(), - e); - } - } - return localCache; - } - - public CatalogClientResourceStore( - @NonNull BlockingResourceStoreClient client, @NonNull File localCache) { - this.remoteStore = client; - setLocalCacheDirectory(localCache); - } - - public void setLocalCacheDirectory(File localCache) { - this.localStore = createLocalStore(localCache); - } - - private FileSystemResourceStore createLocalStore(@NonNull File localCache) { - FileSystemResourceStore local = - new FileSystemResourceStore(localCache) { - @Override - public ResourceNotificationDispatcher getResourceNotificationDispatcher() { - return NullResourceNotificationDispatcher.INSTANCE; - } - }; - local.setLockProvider(new MemoryLockProvider(Runtime.getRuntime().availableProcessors())); - return local; - } - - private Map dumbCache = new ConcurrentHashMap<>(); - - @Override - public CatalogClientResource get(String path) { - try { - // ResourceDescriptor descriptor = remoteStore.describe(path); - ResourceDescriptor descriptor = dumbCache.computeIfAbsent(path, remoteStore::describe); - return toResource(descriptor); - } catch (RuntimeException e) { - e.printStackTrace(); - throw e; - } - } - - @Override - public boolean remove(String path) { - boolean deleted = remoteStore.delete(path); - if (deleted) { - localStore.get(path).delete(); - } - return deleted; - } - - @Override - public boolean move(String path, String target) { - ResourceDescriptor moved = remoteStore.move(path, target).orElse(null); - localStore.move(path, target); - return moved != null && target.equals(moved.getPath()); - } - - @Override - public ResourceNotificationDispatcher getResourceNotificationDispatcher() { - return resourceNotificationDispatcher; - } - - private static class NullResourceNotificationDispatcher - implements ResourceNotificationDispatcher { - - static final NullResourceNotificationDispatcher INSTANCE = - new NullResourceNotificationDispatcher(); - - @Override - public void addListener(String resource, ResourceListener listener) {} - - @Override - public boolean removeListener(String resource, ResourceListener listener) { - return true; - } - - @Override - public void changed(ResourceNotification notification) {} - } - - org.springframework.core.io.Resource getFileContent(String path) throws IOException { - return remoteStore.getFileContent(path); - } - - void put(String path, ByteBuffer contents) { - remoteStore.put(path, contents); - } - - Stream list(String path) { - return remoteStore.list(path).map(this::toResource); - } - - CatalogClientResource toResource(ResourceDescriptor descriptor) { - return new CatalogClientResource(descriptor, this); - } - - /** - * @param catalogServiceResource - * @return - */ - File file(@NonNull CatalogClientResource resource) { - final Resource local = localStore.get(resource.path()); - final CatalogClientResource remote = get(resource.path()); - - if (remote.isDirectory()) { - throw new IllegalStateException(remote.path() + " is a directory"); - } - - boolean localIsFile = Type.RESOURCE.equals(local.getType()); - boolean localAndRemoteUpToDate = resource.lastmodified() == local.lastmodified(); - - if (localIsFile && localAndRemoteUpToDate) { - return local.file(); - } - Lock lock = resource.lock(); - try { - return updateLocalFile(local, remote); - } finally { - lock.release(); - } - } - - File dir(@NonNull CatalogClientResource resource) { - final Resource local = localStore.get(resource.path()); - final CatalogClientResource remote = get(resource.path()); - if (!remote.exists()) { - ResourceDescriptor descriptor = resource.getDescriptor(); - descriptor.setType(Type.DIRECTORY); - ResourceDescriptor created = remoteStore.create(resource.path(), descriptor); - resource = toResource(created); - } - if (remote.isFile()) { - throw new IllegalStateException(remote.path() + " is a file, not a directory"); - } - Lock lock = local.lock(); - try { - boolean localIsDirectory = Type.DIRECTORY.equals(local.getType()); - if (localIsDirectory && !local.delete()) { - throw new IllegalStateException( - "Unable to delete local copy of directory " + resource.path()); - } - File localDirectory = local.dir(); - boolean localAndRemoteUpToDate = resource.lastmodified() == local.lastmodified(); - if (!localAndRemoteUpToDate) { - localDirectory.setLastModified(remote.lastmodified()); - } - return localDirectory; - } finally { - lock.release(); - } - } - - private File updateLocalFile(Resource local, CatalogClientResource remote) { - boolean localExists = local.getType() != Type.UNDEFINED; - if (localExists && !local.delete()) { - throw new IllegalStateException( - "Unable to delete local copy of resource at " + local.path()); - } - File file = local.file(); // forces creation if doesn't exist - if (remote.exists()) { - final long lastModified = remote.lastmodified(); - Assert.state( - lastModified > 0L, - "remote resource claims to exist but last-modified is not set"); - log.debug( - "Updating remote resource {} to local cache: {}", - remote.path(), - file.getAbsolutePath()); - try (InputStream in = remote.in(); - OutputStream out = local.out()) { - ByteStreams.copy(in, out); - log.debug("Local cache updated: {}", file.getAbsolutePath()); - } catch (IOException | RuntimeException e) { - log.error( - "Error trying to copy remote resource {} to local cache {}", - remote.path(), - file.getAbsolutePath(), - e); - local.delete(); - throw e instanceof IOException - ? new UncheckedIOException((IOException) e) - : (RuntimeException) e; - } - file.setLastModified(remote.lastmodified()); - long localLastModified = file.lastModified(); - Assert.state( - lastModified == localLastModified, - String.format( - "last-modified time mismatch, expected %d, was %d", - lastModified, localLastModified)); - } - - return file; - } -} diff --git a/src/catalog/catalog-server/client/src/main/java/org/geoserver/cloud/catalog/client/impl/DeferredResolvingProxy.java b/src/catalog/catalog-server/client/src/main/java/org/geoserver/cloud/catalog/client/impl/DeferredResolvingProxy.java deleted file mode 100644 index 5668c22f5..000000000 --- a/src/catalog/catalog-server/client/src/main/java/org/geoserver/cloud/catalog/client/impl/DeferredResolvingProxy.java +++ /dev/null @@ -1,8 +0,0 @@ -/* - * (c) 2020 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.cloud.catalog.client.impl; - -/** */ -public class DeferredResolvingProxy {} diff --git a/src/catalog/catalog-server/client/src/main/java/org/geoserver/cloud/catalog/client/impl/InnerResolvingProxy.java b/src/catalog/catalog-server/client/src/main/java/org/geoserver/cloud/catalog/client/impl/InnerResolvingProxy.java deleted file mode 100644 index 77625d4fb..000000000 --- a/src/catalog/catalog-server/client/src/main/java/org/geoserver/cloud/catalog/client/impl/InnerResolvingProxy.java +++ /dev/null @@ -1,318 +0,0 @@ -/* - * (c) 2020 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.cloud.catalog.client.impl; - -import lombok.NonNull; -import lombok.RequiredArgsConstructor; -import lombok.extern.slf4j.Slf4j; - -import org.geoserver.catalog.Catalog; -import org.geoserver.catalog.CatalogFacade; -import org.geoserver.catalog.CatalogInfo; -import org.geoserver.catalog.CoverageInfo; -import org.geoserver.catalog.CoverageStoreInfo; -import org.geoserver.catalog.DataStoreInfo; -import org.geoserver.catalog.FeatureTypeInfo; -import org.geoserver.catalog.Info; -import org.geoserver.catalog.LayerGroupInfo; -import org.geoserver.catalog.LayerInfo; -import org.geoserver.catalog.MapInfo; -import org.geoserver.catalog.NamespaceInfo; -import org.geoserver.catalog.PublishedInfo; -import org.geoserver.catalog.ResourceInfo; -import org.geoserver.catalog.StoreInfo; -import org.geoserver.catalog.StyleInfo; -import org.geoserver.catalog.WorkspaceInfo; -import org.geoserver.catalog.impl.LayerGroupInfoImpl; -import org.geoserver.catalog.impl.LayerInfoImpl; -import org.geoserver.catalog.impl.ModificationProxy; -import org.geoserver.catalog.impl.ResolvingProxy; -import org.geoserver.catalog.impl.ResourceInfoImpl; -import org.geoserver.catalog.impl.StoreInfoImpl; -import org.geoserver.catalog.plugin.Patch; -import org.geoserver.config.GeoServerFacade; -import org.geoserver.config.GeoServerInfo; -import org.geoserver.config.LoggingInfo; -import org.geoserver.config.ServiceInfo; -import org.geoserver.config.SettingsInfo; -import org.springframework.lang.Nullable; - -import java.lang.reflect.InvocationHandler; -import java.lang.reflect.Proxy; -import java.util.HashSet; -import java.util.LinkedHashSet; -import java.util.List; -import java.util.Set; - -/** - * Resolves {@link ResolvingProxy} references based only on {@link CatalogInfo#getId() id} using - * {@link CatalogFacade} instead of {@link Catalog} like {@link ResolvingProxy#resolve(Catalog, - * Object)} - */ -@Slf4j -@RequiredArgsConstructor -@Deprecated -public class InnerResolvingProxy { - - private final @NonNull CatalogFacade catalog; - private final @Nullable GeoServerFacade config; - - private boolean failOnNotFound = false; - - /** - * @param fail if {@code true}, a proxied {@link Info} reference that's not found in the catalog - * will result in an {@link IllegalStateException} - * @return {@code this} - */ - public InnerResolvingProxy failOnMissingReference(boolean fail) { - this.failOnNotFound = fail; - return this; - } - - public Patch resolve(Patch patch) { - Patch resolved = new Patch(); - for (Patch.Property p : patch.getPatches()) { - resolved.add(p.getName(), resolvePatchPropertyValue(p.getValue())); - } - return resolved; - } - - private Object resolvePatchPropertyValue(Object orig) { - if (orig instanceof Info info) { - return resolve(info); - } - if (orig instanceof List) { - @SuppressWarnings("unchecked") - List list = (List) orig; - resolve(list); - return list; - } - if (orig instanceof Set) { - @SuppressWarnings("unchecked") - Set set = (Set) orig; - return resolve(set); - } - return orig; - } - - private void resolve(List mutableList) { - for (int i = 0; i < mutableList.size(); i++) { - Object v = mutableList.get(i); - Object resolved = resolvePatchPropertyValue(v); - mutableList.set(i, resolved); - } - } - - private Set resolve(Set set) { - Set target = newSet(set.getClass()); - for (Object value : set) { - target.add(resolvePatchPropertyValue(value)); - } - return target; - } - - @SuppressWarnings("unchecked") - private Set newSet(@SuppressWarnings("rawtypes") Class class1) { - try { - return class1.getConstructor().newInstance(); - } catch (Exception e) { - return new HashSet(); - } - } - - @SuppressWarnings("unchecked") - public T resolve(final T unresolved) { - if (unresolved == null) { - return null; - } - boolean isResolvingProxy = isResolvingProxy(unresolved); - // this should go away, ModificationProxy oughta be at a higher level than - // CatalogFacade/CatalogInfoRepository - T info = ModificationProxy.unwrap(unresolved); - if (isResolvingProxy) { - if (info instanceof CatalogInfo) info = resolveCatalogInfoRef(info); - else if (info instanceof GeoServerInfo) info = (T) this.config.getGlobal(); - else if (info instanceof LoggingInfo) info = (T) this.config.getLogging(); - else if (info instanceof ServiceInfo) - info = (T) this.config.getService(info.getId(), ServiceInfo.class); - } - - if (info == null) { - if (failOnNotFound) - throw new IllegalArgumentException("Reference to " + unresolved.getId()); - return null; - } else if (!Proxy.isProxyClass(info.getClass())) { - if (info instanceof StyleInfo) resolveInternal((StyleInfo) info); - if (info instanceof LayerInfo) resolveInternal((LayerInfo) info); - if (info instanceof LayerGroupInfo) resolveInternal((LayerGroupInfo) info); - if (info instanceof ResourceInfo) resolveInternal((ResourceInfo) info); - if (info instanceof StoreInfo) resolveInternal((StoreInfo) info); - if (info instanceof SettingsInfo) resolveInternal((SettingsInfo) info); - if (info instanceof ServiceInfo) resolveInternal((ServiceInfo) info); - if (info instanceof GeoServerInfo) resolveInternal((GeoServerInfo) info); - if (info instanceof LoggingInfo) resolveInternal((LoggingInfo) info); - } - return info; - } - - @SuppressWarnings("unchecked") - public T resolveCatalogInfoRef(T object) { - InvocationHandler h = Proxy.getInvocationHandler(object); - final String id = ((ResolvingProxy) h).getRef(); - - if (object instanceof WorkspaceInfo) { - return (T) catalog.getWorkspace(id); - } - if (object instanceof NamespaceInfo) { - return (T) catalog.getNamespace(id); - } - if (object instanceof StoreInfo) { - if (object instanceof DataStoreInfo) { - return (T) catalog.getStore(id, DataStoreInfo.class); - } - if (object instanceof CoverageStoreInfo) { - return (T) catalog.getStore(id, CoverageStoreInfo.class); - } - return (T) catalog.getStore(id, StoreInfo.class); - } - if (object instanceof ResourceInfo) { - if (object instanceof FeatureTypeInfo) { - return (T) catalog.getResource(id, FeatureTypeInfo.class); - } - if (object instanceof CoverageInfo) { - return (T) catalog.getResource(id, CoverageInfo.class); - } - return (T) catalog.getResource(id, ResourceInfo.class); - } - if (object instanceof LayerInfo) { - return (T) catalog.getLayer(id); - } - if (object instanceof LayerGroupInfo) { - return (T) catalog.getLayerGroup(id); - } - if (object instanceof PublishedInfo) { - // This can happen if you have a layer group with a null layer (style group) - if (null == id || "".equals(id)) { - return null; - } - } - if (object instanceof StyleInfo) { - return (T) catalog.getStyle(id); - } - if (object instanceof MapInfo) { - return (T) catalog.getMap(id); - } - throw new IllegalArgumentException( - "Unknown CatalogInfo type: " + object.getClass().getCanonicalName()); - } - - protected boolean isResolvingProxy(final T unresolved) { - boolean isProxy = Proxy.isProxyClass(unresolved.getClass()); - boolean isResolvingProxy = false; - if (isProxy) { - InvocationHandler invocationHandler = Proxy.getInvocationHandler(unresolved); - isResolvingProxy = invocationHandler instanceof ResolvingProxy; - } - return isResolvingProxy; - } - - private void resolveInternal(LoggingInfo info) {} - - private void resolveInternal(GeoServerInfo info) {} - - protected void resolveInternal(SettingsInfo settings) { - if (settings.getWorkspace() != null) { - settings.setWorkspace(resolve(settings.getWorkspace())); - } - } - - protected void resolveInternal(ServiceInfo service) { - if (service.getWorkspace() != null) { - service.setWorkspace(resolve(service.getWorkspace())); - } - } - - protected void resolveInternal(LayerInfo layer) { - layer.setResource(resolve(layer.getResource())); - layer.setDefaultStyle(resolve(layer.getDefaultStyle())); - LinkedHashSet styles = new LinkedHashSet(); - for (StyleInfo s : layer.getStyles()) { - styles.add(resolve(s)); - } - ((LayerInfoImpl) layer).setStyles(styles); - } - - protected T resolveInternal(T published) { - if (published instanceof LayerInfo li) resolve(li); - else if (published instanceof LayerGroupInfo lg) resolve(lg); - return published; - } - - protected void resolveInternal(LayerGroupInfo layerGroup) { - LayerGroupInfoImpl lg = (LayerGroupInfoImpl) layerGroup; - - for (int i = 0; i < lg.getLayers().size(); i++) { - PublishedInfo l = lg.getLayers().get(i); - if (l != null) { - lg.getLayers().set(i, resolve(l)); - } - } - - for (int i = 0; i < lg.getStyles().size(); i++) { - StyleInfo s = lg.getStyles().get(i); - if (s != null) { - lg.getStyles().set(i, resolve(s)); - } - } - lg.setWorkspace(resolve(lg.getWorkspace())); - } - - protected StyleInfo resolveInternal(StyleInfo style) { - // resolve the workspace - WorkspaceInfo ws = style.getWorkspace(); - if (ws != null) { - style.setWorkspace(resolve(ws)); - if (style.getWorkspace() == null) { - log.info( - "Failed to resolve workspace for style \"{}\". This means the workspace has not yet been added to the catalog, keep the proxy around", - style.getName()); - } - } - return style; - } - - protected StoreInfo resolveInternal(StoreInfo store) { - StoreInfoImpl s = (StoreInfoImpl) store; - - // resolve the workspace - WorkspaceInfo ws = store.getWorkspace(); - if (ws != null) { - s.setWorkspace(resolve(ws)); - if (store.getWorkspace() == null) { - log.info( - "Failed to resolve workspace for store \"{}\". This means the workspace has not yet been added to the catalog, keep the proxy around", - store.getName()); - } - } - return s; - } - - protected ResourceInfo resolveInternal(ResourceInfo resource) { - ResourceInfoImpl r = (ResourceInfoImpl) resource; - - // resolve the store - StoreInfo store = resource.getStore(); - if (store != null) { - r.setStore(resolve(store)); - } - - // resolve the namespace - NamespaceInfo namespace = resource.getNamespace(); - if (namespace != null) { - r.setNamespace(resolve(namespace)); - } - return r; - } -} diff --git a/src/catalog/catalog-server/client/src/main/java/org/geoserver/cloud/catalog/client/reactivefeign/BlockingResourceStoreClient.java b/src/catalog/catalog-server/client/src/main/java/org/geoserver/cloud/catalog/client/reactivefeign/BlockingResourceStoreClient.java deleted file mode 100644 index a826f99e2..000000000 --- a/src/catalog/catalog-server/client/src/main/java/org/geoserver/cloud/catalog/client/reactivefeign/BlockingResourceStoreClient.java +++ /dev/null @@ -1,69 +0,0 @@ -/* - * (c) 2020 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.cloud.catalog.client.reactivefeign; - -import lombok.NonNull; -import lombok.RequiredArgsConstructor; - -import org.geoserver.cloud.catalog.client.reactivefeign.ReactiveResourceStoreClient.ResourceDescriptor; - -import reactor.core.publisher.Flux; -import reactor.core.publisher.Mono; -import reactor.core.scheduler.Schedulers; - -import java.nio.ByteBuffer; -import java.time.Duration; -import java.util.Optional; -import java.util.concurrent.CompletableFuture; -import java.util.stream.Stream; - -@RequiredArgsConstructor -public class BlockingResourceStoreClient { - - private final @NonNull ReactiveResourceStoreClient client; - - public T block(Mono command) { - return blockOptional(command).orElse(null); - } - - public Optional blockOptional(Mono command) { - if (Schedulers.isInNonBlockingThread()) { - return CompletableFuture.supplyAsync(command::blockOptional).join(); - } - return command.blockOptional(Duration.ofMillis(5000)); - } - - public Stream async(Flux command) { - return command.publishOn(Schedulers.parallel()).toStream(); - } - - public @NonNull ResourceDescriptor describe(String path) { - return block(client.describe(path)); - } - - public @NonNull Stream list(String path) { - return async(client.list(path)); - } - - public @NonNull org.springframework.core.io.Resource getFileContent(String path) { - return block(client.getFileContent(path)); - } - - public @NonNull ResourceDescriptor put(String path, ByteBuffer contents) { - return block(client.put(path, contents)); - } - - public @NonNull ResourceDescriptor create(String path, ResourceDescriptor resource) { - return block(client.create(path, resource)); - } - - public boolean delete(String path) { - return block(client.delete(path)); - } - - public @NonNull Optional move(String path, String target) { - return blockOptional(client.move(path, target)); - } -} diff --git a/src/catalog/catalog-server/client/src/main/java/org/geoserver/cloud/catalog/client/reactivefeign/ReactiveCatalogApiClientConfiguration.java b/src/catalog/catalog-server/client/src/main/java/org/geoserver/cloud/catalog/client/reactivefeign/ReactiveCatalogApiClientConfiguration.java deleted file mode 100644 index 541cf4a89..000000000 --- a/src/catalog/catalog-server/client/src/main/java/org/geoserver/cloud/catalog/client/reactivefeign/ReactiveCatalogApiClientConfiguration.java +++ /dev/null @@ -1,19 +0,0 @@ -/* - * (c) 2020 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.cloud.catalog.client.reactivefeign; - -import org.springframework.context.annotation.Configuration; - -import reactivefeign.spring.config.EnableReactiveFeignClients; - -@Configuration -@EnableReactiveFeignClients( // - defaultConfiguration = ReactiveFeignConfigurationOverrides.class, // - clients = { // - ReactiveCatalogClient.class, // - ReactiveConfigClient.class, // - ReactiveResourceStoreClient.class - }) -public class ReactiveCatalogApiClientConfiguration {} diff --git a/src/catalog/catalog-server/client/src/main/java/org/geoserver/cloud/catalog/client/reactivefeign/ReactiveCatalogClient.java b/src/catalog/catalog-server/client/src/main/java/org/geoserver/cloud/catalog/client/reactivefeign/ReactiveCatalogClient.java deleted file mode 100644 index 6ccf28a17..000000000 --- a/src/catalog/catalog-server/client/src/main/java/org/geoserver/cloud/catalog/client/reactivefeign/ReactiveCatalogClient.java +++ /dev/null @@ -1,178 +0,0 @@ -/* - * (c) 2020 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.cloud.catalog.client.reactivefeign; - -import org.geoserver.catalog.CatalogInfo; -import org.geoserver.catalog.DataStoreInfo; -import org.geoserver.catalog.LayerGroupInfo; -import org.geoserver.catalog.LayerInfo; -import org.geoserver.catalog.NamespaceInfo; -import org.geoserver.catalog.ResourceInfo; -import org.geoserver.catalog.StoreInfo; -import org.geoserver.catalog.StyleInfo; -import org.geoserver.catalog.WorkspaceInfo; -import org.geoserver.catalog.impl.ClassMappings; -import org.geoserver.catalog.plugin.Patch; -import org.geoserver.catalog.plugin.Query; -import org.geotools.api.filter.capability.FunctionName; -import org.springframework.web.bind.annotation.DeleteMapping; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PatchMapping; -import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.PutMapping; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestParam; - -import reactivefeign.spring.config.ReactiveFeignClient; - -import reactor.core.publisher.Flux; -import reactor.core.publisher.Mono; - -@ReactiveFeignClient( // - name = "catalog-service", // - url = "${geoserver.backend.catalog-service.uri:}", // - qualifier = "catalog-client", // - path = "/api/v1/catalog") -public interface ReactiveCatalogClient { - - @PostMapping(path = "/{endpoint}") - Mono create(@PathVariable("endpoint") String endpoint, C info); - - @PatchMapping(path = "/{endpoint}/{id}") - public Mono update( - @PathVariable("endpoint") String endpoint, - @PathVariable("id") String id, - @RequestBody Patch patch); - - @DeleteMapping(path = "/{endpoint}/{id}") - public Mono deleteById( - @PathVariable("endpoint") String endpoint, @PathVariable("id") String id); - - @GetMapping(path = "/{endpoint}") - public Flux findAll( - @PathVariable("endpoint") String endpoint, - @RequestParam(name = "type", required = false) ClassMappings subType); - - @GetMapping(path = {"/{endpoint}/{id}"}) - Mono findById( // - @PathVariable("endpoint") String endpoint, - @PathVariable("id") String id, - @RequestParam(name = "type", required = false) ClassMappings subType); - - @GetMapping(path = "/{endpoint}/name/{name}/first") - Mono findFirstByName( // - @PathVariable("endpoint") String endpoint, - @PathVariable(name = "name") String name, - @RequestParam(name = "type", required = false) ClassMappings subType); - - @GetMapping(path = "/{endpoint}/query/cansortby/{propertyName}") - Mono canSortBy( - @PathVariable("endpoint") String endpoint, - @PathVariable("propertyName") String propertyName); - - @PostMapping(path = "/{endpoint}/query") - Flux query( // - @PathVariable("endpoint") String endpoint, @RequestBody Query query); - - @PostMapping(path = "/{endpoint}/query/count") - Mono count( - @PathVariable("endpoint") String endpoint, @RequestBody Query query); - - @GetMapping(path = "/query/capabilities/functions") - public Flux getSupportedFilterFunctionNames(); - - @PutMapping(path = "/workspaces/default/{workspaceId}") - Mono setDefaultWorkspace(@PathVariable("workspaceId") String workspaceId); - - @DeleteMapping(path = "workspaces/default") - Mono unsetDefaultWorkspace(); - - @GetMapping(path = "/workspaces/default") - Mono getDefaultWorkspace(); - - @PutMapping(path = "namespaces/default/{namespaceId}") - public Mono setDefaultNamespace(@PathVariable("namespaceId") String namespaceId); - - @DeleteMapping(path = "namespaces/default") - Mono unsetDefaultNamespace(); - - @GetMapping(path = "namespaces/default") - Mono getDefaultNamespace(); - - @GetMapping(path = "namespaces/uri") - public Mono findOneNamespaceByURI(@RequestParam("uri") String uri); - - @GetMapping(path = "namespaces/uri/all") - public Flux findAllNamespacesByURI(@RequestParam("uri") String uri); - - @GetMapping(path = "/stores/defaults") - Flux getDefaultDataStores(); - - @PutMapping(path = "/workspaces/{workspaceId}/stores/default/{dataStoreId}") - Mono setDefaultDataStoreByWorkspaceId( // - @PathVariable("workspaceId") String workspaceId, - @PathVariable(name = "dataStoreId") String dataStoreId); - - @DeleteMapping(path = "/workspaces/{workspaceId}/stores/default") - Mono unsetDefaultDataStore( // - @PathVariable("workspaceId") String workspaceId); - - @GetMapping(path = "/workspaces/{workspaceId}/stores/default") - public Mono findDefaultDataStoreByWorkspaceId( // - @PathVariable("workspaceId") String workspaceId); - - @GetMapping(path = "/workspaces/{workspaceId}/stores") - public Flux findStoresByWorkspaceId( // - @PathVariable("workspaceId") String workspaceId, - @RequestParam(name = "type", required = false) ClassMappings subType); - - @GetMapping(path = "/workspaces/{workspaceId}/stores/name/{name}") - public Mono findStoreByWorkspaceIdAndName( // - @PathVariable("workspaceId") String workspaceId, - @PathVariable("name") String name, - @RequestParam(name = "type", required = false) ClassMappings subType); - - @GetMapping(path = "/namespaces/{namespaceId}/resources/name/{name}") - Mono findResourceByNamespaceIdAndName( - @PathVariable("namespaceId") String namespaceId, - @PathVariable("name") String name, - @RequestParam(name = "type", required = false) ClassMappings typeEnum); - - @GetMapping(path = "/layers/style/{styleId}") - Flux findLayersWithStyle(@PathVariable("styleId") String styleId); - - @GetMapping(path = "/layers/resource/{resourceId}") - Flux findLayersByResourceId(@RequestParam("resourceId") String resourceId); - - @GetMapping(path = "/layergroups/noworkspace") - Flux findLayerGroupsByNullWoskspace(); - - @GetMapping(path = "/workspaces/{workspaceId}/layergroups") - Flux findLayerGroupsByWoskspaceId( - @PathVariable("workspaceId") String workspaceId); - - @GetMapping(path = "/layergroups/noworkspace/{name}") - Mono findLayerGroupByNameAndNullWorkspace(@PathVariable("name") String name); - - @GetMapping(path = "/workspaces/{workspaceId}/layergroups/{name}") - Mono findLayerGroupByWorkspaceIdAndName( - @PathVariable(required = false, name = "workspaceId") String workspaceId, - @PathVariable("name") String name); - - @GetMapping(path = "/styles/noworkspace") - Flux findStylesByNullWorkspace(); - - @GetMapping(path = "/workspaces/{workspaceId}/styles") - Flux findStylesByWorkspaceId(@PathVariable(name = "workspaceId") String workspaceId); - - @GetMapping(path = "/workspaces/{workspaceId}/styles/{name}") - public Mono findStyleByWorkspaceIdAndName( - @PathVariable(name = "workspaceId") String workspaceId, - @PathVariable("name") String name); - - @GetMapping(path = "/styles/noworkspace/{name}") - Mono findStyleByNameAndNullWorkspace(@PathVariable("name") String name); -} diff --git a/src/catalog/catalog-server/client/src/main/java/org/geoserver/cloud/catalog/client/reactivefeign/ReactiveConfigClient.java b/src/catalog/catalog-server/client/src/main/java/org/geoserver/cloud/catalog/client/reactivefeign/ReactiveConfigClient.java deleted file mode 100644 index 756a86ebd..000000000 --- a/src/catalog/catalog-server/client/src/main/java/org/geoserver/cloud/catalog/client/reactivefeign/ReactiveConfigClient.java +++ /dev/null @@ -1,118 +0,0 @@ -/* - * (c) 2020 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.cloud.catalog.client.reactivefeign; - -import org.geoserver.catalog.plugin.Patch; -import org.geoserver.config.GeoServerInfo; -import org.geoserver.config.LoggingInfo; -import org.geoserver.config.ServiceInfo; -import org.geoserver.config.SettingsInfo; -import org.springframework.web.bind.annotation.DeleteMapping; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PatchMapping; -import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.PutMapping; -import org.springframework.web.bind.annotation.RequestBody; - -import reactivefeign.spring.config.ReactiveFeignClient; - -import reactor.core.publisher.Flux; -import reactor.core.publisher.Mono; - -@ReactiveFeignClient( // - name = "catalog-service", // - url = "${geoserver.backend.catalog-service.uri:}", // - qualifier = "config-client", // - path = "/api/v1/config") -public interface ReactiveConfigClient { - - /** The global geoserver configuration. */ - @GetMapping("/global") - Mono getGlobal(); - - /** Sets the global configuration. */ - @PutMapping("/global") - Mono setGlobal(@RequestBody GeoServerInfo global); - - /** The settings configuration by its id, or null if not exists. */ - @GetMapping("/workspaces/settings/{id}") - Mono getSettingsById(@PathVariable("id") String id); - - /** - * The settings configuration for the specified workspace, or null if not exists. - */ - @GetMapping("/workspaces/{workspaceId}/settings") - Mono getSettingsByWorkspace(@PathVariable("workspaceId") String workspaceId); - - /** Adds a settings configuration for the specified workspace. */ - @PostMapping("/workspaces/{workspaceId}/settings") - Mono createSettings( - @PathVariable("workspaceId") String workspaceId, @RequestBody SettingsInfo settings); - - /** Saves the settings configuration for the specified workspace. */ - @PatchMapping("/workspaces/{workspaceId}/settings") - Mono updateSettings( - @PathVariable("workspaceId") String workspaceId, @RequestBody Patch patch); - - /** Removes the settings configuration for the specified workspace. */ - @DeleteMapping("/workspaces/{workspaceId}/settings") - Mono deleteSettings(@PathVariable("workspaceId") String workspaceId); - - /** The logging configuration. */ - @GetMapping("/logging") - Mono getLogging(); - - /** Sets logging configuration. */ - @PutMapping("/logging") - Mono setLogging(@RequestBody LoggingInfo logging); - - /** Adds a service to the configuration. */ - @PostMapping("/services") - Mono createService(@RequestBody ServiceInfo service); - - @PostMapping("/workspaces/{workspaceId}/services") - Mono createService( - @PathVariable("workspaceId") String workspaceId, @RequestBody ServiceInfo service); - - /** Removes a service from the configuration. */ - @DeleteMapping("/services/{serviceId}") - Mono deleteService(@PathVariable("serviceId") String serviceId); - - /** Looks up a global service by id. */ - @GetMapping("/services/{serviceId}") - Mono getServiceById(@PathVariable("serviceId") String id); - - /** Saves a service that has been modified. */ - @PatchMapping("/services/{serviceId}") - Mono updateService( - @PathVariable("serviceId") String serviceId, @RequestBody Patch patch); - - /** GeoServer services specific to the specified workspace. */ - @GetMapping("/workspaces/{workspaceId}/services") - Flux getServicesByWorkspace(@PathVariable("workspaceId") String workspaceId); - - /** Global (no-workspace) services. */ - @GetMapping("/services") - Flux getGlobalServices(); - - /** GeoServer global service filtered by class. */ - @GetMapping("/services/type/{type}") - Mono getGlobalServiceByType(@PathVariable("type") String clazz); - - /** GeoServer service specific to the specified workspace and filtered by class. */ - @GetMapping("/workspaces/{workspaceId}/services/type/{type}") - Mono getServiceByWorkspaceAndType( - @PathVariable("workspaceId") String workspaceId, @PathVariable("type") String clazz); - - /** Looks up a service by name. */ - @GetMapping("/services/name/{name}") - Mono getGlobalServiceByName(@PathVariable("name") String name); - - /** Looks up a service by name, specific to the specified workspace. */ - @GetMapping("/workspaces/{workspaceId}/services/name/{name}") - Mono getServiceByWorkspaceAndName( - @PathVariable("workspaceId") String workspaceId, @PathVariable("name") String name); -} diff --git a/src/catalog/catalog-server/client/src/main/java/org/geoserver/cloud/catalog/client/reactivefeign/ReactiveFeignConfigurationOverrides.java b/src/catalog/catalog-server/client/src/main/java/org/geoserver/cloud/catalog/client/reactivefeign/ReactiveFeignConfigurationOverrides.java deleted file mode 100644 index c9f4c4d95..000000000 --- a/src/catalog/catalog-server/client/src/main/java/org/geoserver/cloud/catalog/client/reactivefeign/ReactiveFeignConfigurationOverrides.java +++ /dev/null @@ -1,42 +0,0 @@ -/* - * (c) 2020 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.cloud.catalog.client.reactivefeign; - -import feign.Contract; -import feign.MethodMetadata; - -import lombok.NonNull; -import lombok.RequiredArgsConstructor; - -import org.springframework.cloud.openfeign.support.SpringMvcContract; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; - -import java.util.List; - -@Configuration -public class ReactiveFeignConfigurationOverrides { - - @Bean - Contract reactiveFeignClientContract() { - return new FallbackContract(new SpringMvcContract(), new Contract.Default()); - } - - @RequiredArgsConstructor - private static class FallbackContract implements Contract { - - private final @NonNull Contract primary; - private final @NonNull Contract fallback; - - @Override - public List parseAndValidateMetadata(Class targetType) { - try { - return primary.parseAndValidateMetadata(targetType); - } catch (RuntimeException e) { - return fallback.parseAndValidateMetadata(targetType); - } - } - } -} diff --git a/src/catalog/catalog-server/client/src/main/java/org/geoserver/cloud/catalog/client/reactivefeign/ReactiveResourceStoreClient.java b/src/catalog/catalog-server/client/src/main/java/org/geoserver/cloud/catalog/client/reactivefeign/ReactiveResourceStoreClient.java deleted file mode 100644 index 527a45e67..000000000 --- a/src/catalog/catalog-server/client/src/main/java/org/geoserver/cloud/catalog/client/reactivefeign/ReactiveResourceStoreClient.java +++ /dev/null @@ -1,83 +0,0 @@ -/* - * (c) 2020 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.cloud.catalog.client.reactivefeign; - -import feign.Headers; -import feign.Param; -import feign.RequestLine; - -import lombok.Data; -import lombok.NoArgsConstructor; - -import org.geoserver.platform.resource.Paths; -import org.geoserver.platform.resource.Resource; -import org.geoserver.platform.resource.Resource.Type; -import org.geoserver.platform.resource.ResourceStore; - -import reactivefeign.spring.config.ReactiveFeignClient; - -import reactor.core.publisher.Flux; -import reactor.core.publisher.Mono; - -import java.nio.ByteBuffer; - -/** Catalog-service client to support {@link ResourceStore} */ -@ReactiveFeignClient( // - name = "catalog-service", // - url = "${geoserver.backend.catalog-service.uri:}", // - qualifier = "resource-store-client", // - path = "/api/v1/resources" // - // , fallbackFactory = ResourceStoreFallbackFactory.class - ) -public interface ReactiveResourceStoreClient { - - @Data - @NoArgsConstructor - class ResourceDescriptor { - private String path = Paths.BASE; - private Resource.Type type = Type.UNDEFINED; - private long lastModified; - - public static ResourceDescriptor valueOf(Resource resource) { - ResourceDescriptor d = new ResourceDescriptor(); - d.setType(resource.getType()); - d.setPath(resource.path()); - d.setLastModified(resource.lastmodified()); - return d; - } - - public void setPath(String path) { - this.path = path == null ? Paths.BASE : path; - } - } - - @RequestLine(value = "GET /{path}", decodeSlash = false) - @Headers({"Accept: application/json"}) - Mono describe(@Param("path") String path); - - @RequestLine(value = "GET /{path}", decodeSlash = false) - @Headers("Accept: application/stream+json") - Flux list(@Param("path") String path); - - @RequestLine(value = "GET /{path}", decodeSlash = false) - @Headers("Accept: application/octet-stream") - Mono getFileContent(@Param("path") String path); - - @RequestLine(value = "PUT /{path}", decodeSlash = false) - @Headers({"Content-Type: application/octet-stream", "Accept: application/json"}) - Mono put(@Param("path") String path, ByteBuffer contents); - - @RequestLine(value = "POST /{path}", decodeSlash = false) - @Headers({"Content-Type: application/json", "Accept: application/json"}) - Mono create(@Param("path") String path, ResourceDescriptor resource); - - @RequestLine(value = "DELETE /{path}", decodeSlash = false) - @Headers({"Accept: application/json"}) - Mono delete(@Param("path") String path); - - @RequestLine(value = "POST /move/{path}?to={target}", decodeSlash = false) - @Headers("Accept: application/json") - Mono move(@Param("path") String path, @Param("target") String target); -} diff --git a/src/catalog/catalog-server/client/src/main/java/org/geoserver/cloud/catalog/client/repository/CatalogClientConfigRepository.java b/src/catalog/catalog-server/client/src/main/java/org/geoserver/cloud/catalog/client/repository/CatalogClientConfigRepository.java deleted file mode 100644 index c738db483..000000000 --- a/src/catalog/catalog-server/client/src/main/java/org/geoserver/cloud/catalog/client/repository/CatalogClientConfigRepository.java +++ /dev/null @@ -1,189 +0,0 @@ -/* - * (c) 2020 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.cloud.catalog.client.repository; - -import lombok.Getter; -import lombok.Setter; - -import org.geoserver.catalog.Info; -import org.geoserver.catalog.WorkspaceInfo; -import org.geoserver.catalog.plugin.Patch; -import org.geoserver.cloud.catalog.client.reactivefeign.ReactiveConfigClient; -import org.geoserver.config.GeoServerInfo; -import org.geoserver.config.LoggingInfo; -import org.geoserver.config.ServiceInfo; -import org.geoserver.config.SettingsInfo; -import org.geoserver.config.plugin.ConfigRepository; - -import reactor.core.publisher.Mono; -import reactor.core.scheduler.Schedulers; - -import java.lang.reflect.Proxy; -import java.util.Optional; -import java.util.concurrent.CompletableFuture; -import java.util.stream.Stream; - -/** */ -public class CatalogClientConfigRepository implements ConfigRepository { - - private @Getter @Setter ReactiveConfigClient client; - - public CatalogClientConfigRepository() {} - - public CatalogClientConfigRepository(ReactiveConfigClient configClient) { - this.client = configClient; - } - - protected void block(Mono call) { - if (Schedulers.isInNonBlockingThread()) { - CompletableFuture.supplyAsync(call::block).join(); - } - call.block(); - } - - protected Optional blockAndReturn(Mono call) { - if (Schedulers.isInNonBlockingThread()) { - return CompletableFuture.supplyAsync(call::blockOptional).join(); - } - return call.blockOptional(); - } - - @Override - public Optional getGlobal() { - return blockAndReturn(client.getGlobal()); - } - - @Override - public void setGlobal(GeoServerInfo global) { - checkNotAProxy(global); - blockAndReturn(client.setGlobal(global)); - } - - @Override - public Optional getSettingsById(String id) { - return blockAndReturn(client.getSettingsById(id)); - } - - @Override - public Optional getSettingsByWorkspace(WorkspaceInfo workspace) { - return blockAndReturn(client.getSettingsByWorkspace(workspace.getId())); - } - - @Override - public void add(SettingsInfo settings) { - checkNotAProxy(settings); - blockAndReturn(client.createSettings(settings.getWorkspace().getId(), settings)); - } - - @Override - public SettingsInfo update(SettingsInfo settings, Patch patch) { - return blockAndReturn(client.updateSettings(settings.getWorkspace().getId(), patch)) - .orElseThrow(() -> new IllegalStateException()); - } - - @Override - public void remove(SettingsInfo settings) { - blockAndReturn(client.deleteSettings(settings.getWorkspace().getId())); - } - - @Override - public Optional getLogging() { - return blockAndReturn(client.getLogging()); - } - - @Override - public void setLogging(LoggingInfo logging) { - checkNotAProxy(logging); - blockAndReturn(client.setLogging(logging)); - } - - @Override - public void add(ServiceInfo service) { - checkNotAProxy(service); - WorkspaceInfo workspace = service.getWorkspace(); - if (workspace == null) { - blockAndReturn(client.createService(service)); - } else { - blockAndReturn(client.createService(workspace.getId(), service)); - } - } - - @Override - public void remove(ServiceInfo service) { - client.deleteService(service.getId()); - } - - @SuppressWarnings("unchecked") - @Override - public S update(S service, Patch patch) { - Optional updated = - blockAndReturn(client.updateService(service.getId(), patch)); - return updated.map(u -> (S) u).orElseThrow(() -> new IllegalStateException()); - } - - @Override - public Stream getGlobalServices() { - return client.getGlobalServices().toStream(); - } - - @Override - public Stream getServicesByWorkspace(WorkspaceInfo workspace) { - return client.getServicesByWorkspace(workspace.getId()).toStream(); - } - - @Override - public Optional getGlobalService(Class clazz) { - String typeName = interfaceName(clazz); - return blockAndReturn(client.getGlobalServiceByType(typeName).map(clazz::cast)); - } - - @Override - public Optional getServiceByWorkspace( - WorkspaceInfo workspace, Class clazz) { - String typeName = interfaceName(clazz); - return blockAndReturn( - client.getServiceByWorkspaceAndType(workspace.getId(), typeName).map(clazz::cast)); - } - - @Override - public Optional getServiceById(String id, Class clazz) { - return blockAndReturn(client.getServiceById(id).filter(clazz::isInstance).map(clazz::cast)); - } - - @Override - public Optional getServiceByName(String name, Class clazz) { - return blockAndReturn( - client.getGlobalServiceByName(name).filter(clazz::isInstance).map(clazz::cast)); - } - - @Override - public Optional getServiceByNameAndWorkspace( - String name, WorkspaceInfo workspace, Class clazz) { - return blockAndReturn( - client.getServiceByWorkspaceAndName(workspace.getId(), name) - .filter(clazz::isInstance) - .map(clazz::cast)); - } - - /** no-op */ - @Override - public void dispose() { - // no-op - } - - protected String interfaceName(Class clazz) { - if (!clazz.isInterface()) - throw new IllegalArgumentException("Expected interface type, got " + clazz); - String typeName = clazz.getName(); - return typeName; - } - - private static void checkNotAProxy(Info value) { - if (Proxy.isProxyClass(value.getClass())) { - throw new IllegalArgumentException( - "Proxy values shall not be passed to DefaultConfigRepository"); - } - } -} diff --git a/src/catalog/catalog-server/client/src/main/java/org/geoserver/cloud/catalog/client/repository/CatalogClientFilterSupport.java b/src/catalog/catalog-server/client/src/main/java/org/geoserver/cloud/catalog/client/repository/CatalogClientFilterSupport.java deleted file mode 100644 index 7e2f47f74..000000000 --- a/src/catalog/catalog-server/client/src/main/java/org/geoserver/cloud/catalog/client/repository/CatalogClientFilterSupport.java +++ /dev/null @@ -1,133 +0,0 @@ -/* - * (c) 2020 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.cloud.catalog.client.repository; - -import lombok.NonNull; -import lombok.RequiredArgsConstructor; -import lombok.Value; -import lombok.experimental.Accessors; - -import org.geotools.api.filter.Filter; -import org.geotools.api.filter.Id; -import org.geotools.api.filter.PropertyIsBetween; -import org.geotools.api.filter.PropertyIsLike; -import org.geotools.api.filter.PropertyIsNil; -import org.geotools.api.filter.PropertyIsNull; -import org.geotools.api.filter.capability.FilterCapabilities; -import org.geotools.api.filter.capability.FunctionName; -import org.geotools.api.filter.expression.Add; -import org.geotools.api.filter.expression.Divide; -import org.geotools.api.filter.expression.Multiply; -import org.geotools.api.filter.expression.Subtract; -import org.geotools.api.filter.spatial.BBOX; -import org.geotools.api.filter.spatial.Beyond; -import org.geotools.api.filter.spatial.Contains; -import org.geotools.api.filter.spatial.Crosses; -import org.geotools.api.filter.spatial.DWithin; -import org.geotools.api.filter.spatial.Disjoint; -import org.geotools.api.filter.spatial.Equals; -import org.geotools.api.filter.spatial.Intersects; -import org.geotools.api.filter.spatial.Overlaps; -import org.geotools.api.filter.spatial.Touches; -import org.geotools.api.filter.spatial.Within; -import org.geotools.api.filter.temporal.After; -import org.geotools.api.filter.temporal.AnyInteracts; -import org.geotools.api.filter.temporal.Before; -import org.geotools.api.filter.temporal.Begins; -import org.geotools.api.filter.temporal.BegunBy; -import org.geotools.api.filter.temporal.During; -import org.geotools.api.filter.temporal.EndedBy; -import org.geotools.api.filter.temporal.Ends; -import org.geotools.api.filter.temporal.Meets; -import org.geotools.api.filter.temporal.MetBy; -import org.geotools.api.filter.temporal.OverlappedBy; -import org.geotools.api.filter.temporal.TContains; -import org.geotools.api.filter.temporal.TEquals; -import org.geotools.api.filter.temporal.TOverlaps; -import org.geotools.filter.Capabilities; -import org.geotools.filter.visitor.CapabilitiesFilterSplitter; - -import java.util.List; - -/** */ -@RequiredArgsConstructor -@Accessors(fluent = true, chain = true) -public class CatalogClientFilterSupport { - - public static final FilterCapabilities CAPABILITIES; - - static { - Capabilities builder = new Capabilities(); - builder.addAll(Capabilities.LOGICAL); - builder.addAll(Capabilities.SIMPLE_COMPARISONS); - builder.addType(Id.class); - builder.addType(PropertyIsNil.class); - builder.addType(PropertyIsNull.class); - builder.addType(PropertyIsLike.class); - builder.addType(PropertyIsBetween.class); - - builder.addName(Add.NAME); - builder.addName(Subtract.NAME); - builder.addName(Multiply.NAME); - builder.addName(Divide.NAME); - - builder.addType(BBOX.class); - builder.addType(Contains.class); - builder.addType(Crosses.class); - builder.addType(Disjoint.class); - builder.addType(Beyond.class); - builder.addType(DWithin.class); - builder.addType(Equals.class); - builder.addType(Intersects.class); - builder.addType(Overlaps.class); - builder.addType(Touches.class); - builder.addType(Within.class); - - builder.addType(After.class); - builder.addType(AnyInteracts.class); - builder.addType(Before.class); - builder.addType(Begins.class); - builder.addType(BegunBy.class); - builder.addType(During.class); - builder.addType(EndedBy.class); - builder.addType(Ends.class); - builder.addType(Meets.class); - builder.addType(MetBy.class); - builder.addType(OverlappedBy.class); - builder.addType(TContains.class); - builder.addType(TEquals.class); - builder.addType(TOverlaps.class); - - CAPABILITIES = builder.getContents(); - } - - private Capabilities capabilities; - - public CatalogClientFilterSupport(@NonNull List supportedServerFunctions) { - capabilities = createCapabilities(supportedServerFunctions); - } - - public static @Value class PrePostFilterTuple { - private final @NonNull Filter pre; - private final @NonNull Filter post; - } - - public PrePostFilterTuple split(@NonNull Filter filter) { - CapabilitiesFilterSplitter splitter = - new CapabilitiesFilterSplitter(capabilities, null, null); - filter.accept(splitter, null); - return new PrePostFilterTuple(splitter.getFilterPre(), splitter.getFilterPost()); - } - - private static Capabilities createCapabilities(List supportedFunctionNames) { - Capabilities builder = new Capabilities(CAPABILITIES); - for (FunctionName fn : supportedFunctionNames) { - String name = fn.getName(); - int argumentCount = fn.getArgumentCount(); - builder.addName(name, argumentCount); - } - return builder; - } -} diff --git a/src/catalog/catalog-server/client/src/main/java/org/geoserver/cloud/catalog/client/repository/CatalogClientLayerGroupRepository.java b/src/catalog/catalog-server/client/src/main/java/org/geoserver/cloud/catalog/client/repository/CatalogClientLayerGroupRepository.java deleted file mode 100644 index 93a417320..000000000 --- a/src/catalog/catalog-server/client/src/main/java/org/geoserver/cloud/catalog/client/repository/CatalogClientLayerGroupRepository.java +++ /dev/null @@ -1,44 +0,0 @@ -/* - * (c) 2020 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.cloud.catalog.client.repository; - -import lombok.Getter; -import lombok.NonNull; - -import org.geoserver.catalog.LayerGroupInfo; -import org.geoserver.catalog.WorkspaceInfo; -import org.geoserver.catalog.plugin.CatalogInfoRepository.LayerGroupRepository; - -import java.util.Objects; -import java.util.Optional; -import java.util.stream.Stream; - -public class CatalogClientLayerGroupRepository extends CatalogClientRepository - implements LayerGroupRepository { - - private final @Getter Class contentType = LayerGroupInfo.class; - - @Override - public Stream findAllByWorkspaceIsNull() { - return toStream(client().findLayerGroupsByNullWoskspace()); - } - - @Override - public Stream findAllByWorkspace(@NonNull WorkspaceInfo workspace) { - return toStream(client().findLayerGroupsByWoskspaceId(workspace.getId())); - } - - @Override - public Optional findByNameAndWorkspaceIsNull(@NonNull String name) { - return blockAndReturn(client().findLayerGroupByNameAndNullWorkspace(name)); - } - - @Override - public Optional findByNameAndWorkspace( - @NonNull String name, @NonNull WorkspaceInfo workspace) { - Objects.requireNonNull(workspace.getId()); - return blockAndReturn(client().findLayerGroupByWorkspaceIdAndName(workspace.getId(), name)); - } -} diff --git a/src/catalog/catalog-server/client/src/main/java/org/geoserver/cloud/catalog/client/repository/CatalogClientLayerRepository.java b/src/catalog/catalog-server/client/src/main/java/org/geoserver/cloud/catalog/client/repository/CatalogClientLayerRepository.java deleted file mode 100644 index 08a34427f..000000000 --- a/src/catalog/catalog-server/client/src/main/java/org/geoserver/cloud/catalog/client/repository/CatalogClientLayerRepository.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * (c) 2020 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.cloud.catalog.client.repository; - -import lombok.Getter; -import lombok.NonNull; - -import org.geoserver.catalog.LayerInfo; -import org.geoserver.catalog.ResourceInfo; -import org.geoserver.catalog.StyleInfo; -import org.geoserver.catalog.plugin.CatalogInfoRepository.LayerRepository; - -import java.util.Optional; -import java.util.stream.Stream; - -public class CatalogClientLayerRepository extends CatalogClientRepository - implements LayerRepository { - - private final @Getter Class contentType = LayerInfo.class; - - @Override - public Stream findAllByDefaultStyleOrStyles(StyleInfo style) { - return toStream(client().findLayersWithStyle(style.getId())); - } - - @Override - public Stream findAllByResource(ResourceInfo resource) { - return toStream(client().findLayersByResourceId(resource.getId())); - } - - @Override - public Optional findOneByName(@NonNull String name) { - return findFirstByName(name, LayerInfo.class); - } -} diff --git a/src/catalog/catalog-server/client/src/main/java/org/geoserver/cloud/catalog/client/repository/CatalogClientMapRepository.java b/src/catalog/catalog-server/client/src/main/java/org/geoserver/cloud/catalog/client/repository/CatalogClientMapRepository.java deleted file mode 100644 index 41ebf4e09..000000000 --- a/src/catalog/catalog-server/client/src/main/java/org/geoserver/cloud/catalog/client/repository/CatalogClientMapRepository.java +++ /dev/null @@ -1,16 +0,0 @@ -/* - * (c) 2020 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.cloud.catalog.client.repository; - -import lombok.Getter; - -import org.geoserver.catalog.MapInfo; -import org.geoserver.catalog.plugin.CatalogInfoRepository.MapRepository; - -public class CatalogClientMapRepository extends CatalogClientRepository - implements MapRepository { - - private final @Getter Class contentType = MapInfo.class; -} diff --git a/src/catalog/catalog-server/client/src/main/java/org/geoserver/cloud/catalog/client/repository/CatalogClientNamespaceRepository.java b/src/catalog/catalog-server/client/src/main/java/org/geoserver/cloud/catalog/client/repository/CatalogClientNamespaceRepository.java deleted file mode 100644 index bb88bfa3a..000000000 --- a/src/catalog/catalog-server/client/src/main/java/org/geoserver/cloud/catalog/client/repository/CatalogClientNamespaceRepository.java +++ /dev/null @@ -1,58 +0,0 @@ -/* - * (c) 2020 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.cloud.catalog.client.repository; - -import lombok.Getter; -import lombok.NonNull; - -import org.geoserver.catalog.NamespaceInfo; -import org.geoserver.catalog.plugin.CatalogInfoRepository.NamespaceRepository; -import org.springframework.lang.Nullable; - -import java.util.Objects; -import java.util.Optional; -import java.util.stream.Stream; - -public class CatalogClientNamespaceRepository extends CatalogClientRepository - implements NamespaceRepository { - - private final @Getter Class contentType = NamespaceInfo.class; - - @Override - public void setDefaultNamespace(@NonNull NamespaceInfo namespace) { - Objects.requireNonNull(namespace.getId(), "provided null namespace id"); - blockAndReturn(client().setDefaultNamespace(namespace.getId())); - } - - @Override - public Optional findFirstByName( - @NonNull String name, @NonNull Class infoType) { - // geoserver has this tendency to loose method contracts... - if (name.indexOf(':') > -1) { - return Optional.empty(); - } - return super.findFirstByName(name, infoType); - } - - @Override - public void unsetDefaultNamespace() { - block(client().unsetDefaultNamespace()); - } - - @Override - public @Nullable Optional getDefaultNamespace() { - return blockAndReturn(client().getDefaultNamespace()); - } - - @Override - public @Nullable Optional findOneByURI(@NonNull String uri) { - return blockAndReturn(client().findOneNamespaceByURI(uri)); - } - - @Override - public Stream findAllByURI(@NonNull String uri) { - return toStream(client().findAllNamespacesByURI(uri)); - } -} diff --git a/src/catalog/catalog-server/client/src/main/java/org/geoserver/cloud/catalog/client/repository/CatalogClientRepository.java b/src/catalog/catalog-server/client/src/main/java/org/geoserver/cloud/catalog/client/repository/CatalogClientRepository.java deleted file mode 100644 index 642baf293..000000000 --- a/src/catalog/catalog-server/client/src/main/java/org/geoserver/cloud/catalog/client/repository/CatalogClientRepository.java +++ /dev/null @@ -1,264 +0,0 @@ -/* - * (c) 2020 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.cloud.catalog.client.repository; - -import static org.geotools.filter.visitor.SimplifyingFilterVisitor.simplify; - -import lombok.NonNull; -import lombok.Setter; -import lombok.extern.slf4j.Slf4j; - -import org.geoserver.catalog.CatalogInfo; -import org.geoserver.catalog.Info; -import org.geoserver.catalog.impl.ClassMappings; -import org.geoserver.catalog.impl.ResolvingProxy; -import org.geoserver.catalog.plugin.CatalogInfoRepository; -import org.geoserver.catalog.plugin.Patch; -import org.geoserver.catalog.plugin.Query; -import org.geoserver.cloud.catalog.client.reactivefeign.ReactiveCatalogClient; -import org.geoserver.cloud.catalog.client.repository.CatalogClientFilterSupport.PrePostFilterTuple; -import org.geotools.api.filter.Filter; -import org.geotools.api.filter.capability.FunctionName; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.lang.Nullable; - -import reactor.core.publisher.Flux; -import reactor.core.publisher.Mono; -import reactor.core.scheduler.Schedulers; - -import java.util.Collections; -import java.util.List; -import java.util.Optional; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ConcurrentMap; -import java.util.function.Function; -import java.util.function.Predicate; -import java.util.function.Supplier; -import java.util.stream.Stream; - -@Slf4j -public abstract class CatalogClientRepository - implements CatalogInfoRepository { - - private ReactiveCatalogClient client; - - private @Setter Function objectResolver = Function.identity(); - private @Setter Supplier> streamResolver = - () -> Function.identity(); - - /** Don't use but through {@link #endpoint()} */ - private String _endpoint; - - /** - * Splits {@link Query} filters into server-side supported and client-side post-processing - * filters. Used and created lazily by {@link #findAll(Query)} - */ - private CatalogClientFilterSupport filterSupport; - - protected ReactiveCatalogClient client() { - return client; - } - - protected String endpoint() { - if (_endpoint == null) { - this._endpoint = - ClassMappings.fromInterface(getContentType()).name().toLowerCase() + "s"; - } - return _endpoint; - } - - @Autowired - public void setClient(ReactiveCatalogClient client) { - this.client = client; - } - - @SuppressWarnings("unchecked") - protected Function proxyResolver() { - return (Function) this.objectResolver; - } - - /** - * Resolves {@link ResolvingProxy resolving proxy} properties of {@code incoming}. The object - * coming from the wire has all properties that are subtypes of {@link Info} "proxified" and - * need to be resolved to the real ones before leaving this class - */ - protected C resolve(C incoming) { - Function pr = proxyResolver(); - C resolved = pr.apply(incoming); - return resolved; - } - - /** - * Converts the Flux to a stream and applies {@link #proxyResolver()} function to each element - * using a {@link MemoizingResolver} so the same reference is not requested multiple times to - * the backend service while the stream is consumed - */ - protected Stream toStream(Flux flux) { - @SuppressWarnings("unchecked") - Function resolver = (Function) this.streamResolver.get(); - Stream resolvingStream = flux.toStream().map(resolver::apply); - return resolvingStream; - } - - protected void block(Mono call) { - if (Schedulers.isInNonBlockingThread()) { - CompletableFuture.supplyAsync(call::block).join(); - } - call.block(); - } - - protected Optional blockOptional(Mono call) { - Optional object; - if (Schedulers.isInNonBlockingThread()) { - object = CompletableFuture.supplyAsync(call::blockOptional).join(); - } else { - object = call.blockOptional(); - } - return object; - } - - protected Optional blockAndReturn(Mono call) { - Optional object = blockOptional(call); - return object.map(this::resolve); - } - - private final ConcurrentMap positiveCanSortByCache = new ConcurrentHashMap<>(); - - @Override - public boolean canSortBy(@NonNull String propertyName) { - Boolean canSort = positiveCanSortByCache.computeIfAbsent(propertyName, this::callCanSort); - return canSort == null ? false : canSort.booleanValue(); - } - - private @Nullable Boolean callCanSort(String propertyName) { - String endpoint = endpoint(); - Boolean canSort = client().canSortBy(endpoint, propertyName).toFuture().join(); - return canSort.booleanValue() ? Boolean.TRUE : null; - } - - @Override - public void add(@NonNull CI value) { - blockAndReturn(client.create(endpoint(), value)); - } - - @Override - public void remove(@NonNull CI value) { - blockAndReturn(client.deleteById(endpoint(), value.getId())); - } - - @Override - public T update(@NonNull T value, @NonNull Patch patch) { - Mono updated = client.update(endpoint(), value.getId(), patch); - return blockAndReturn(updated).get(); - } - - @Override - public Optional findFirstByName( - @NonNull String name, @NonNull Class infoType) { - ClassMappings typeArg = typeEnum(infoType); - Mono found = client.findFirstByName(endpoint(), name, typeArg); - return blockAndReturn(found); - } - - @Override - public Stream findAll() { - ClassMappings typeArg = typeEnum(getContentType()); - Flux flux = client.findAll(endpoint(), typeArg); - return toStream(flux); - } - - @Override - public Stream findAll(Query query) { - final Filter rawFilter = query.getFilter(); - if (Filter.EXCLUDE.equals(rawFilter)) { - return Stream.empty(); // don't even bother - } - PrePostFilterTuple filters = getFilterSupport().split(rawFilter); - Filter supportedFilter = simplify(filters.pre()); - Filter unsupportedFilter = simplify(filters.post()); - if (!Filter.INCLUDE.equals(supportedFilter)) { - log.debug( - "Querying {}'s with filter {}", - query.getType().getSimpleName(), - supportedFilter); - } - query = query.withFilter(supportedFilter); - return query(query, unsupportedFilter); - } - - protected Stream query(Query query, Filter unsupportedFilter) { - Stream stream = toStream(client.query(endpoint(), query)); - if (!Filter.INCLUDE.equals(unsupportedFilter)) { - log.debug("Post-filtering with {}", unsupportedFilter); - Predicate predicate = info -> unsupportedFilter.evaluate(info); - stream = stream.filter(predicate); - } - return stream; - } - - @Override - public long count(@NonNull Class of, @NonNull Filter rawFilter) { - if (Filter.EXCLUDE.equals(rawFilter)) { - return 0L; - } - PrePostFilterTuple filters = getFilterSupport().split(rawFilter); - Filter supportedFilter = simplify(filters.pre()); - Filter unsupportedFilter = simplify(filters.post()); - Query query = Query.valueOf(of, supportedFilter); - if (Filter.INCLUDE.equals(unsupportedFilter)) { - return blockOptional(client().count(endpoint(), query)).orElse(Long.valueOf(0)); - } - return query(query, unsupportedFilter).count(); - } - - private CatalogClientFilterSupport getFilterSupport() { - if (this.filterSupport == null) { - List serverFuncions = getServerSupportedFunctions(); - this.filterSupport = new CatalogClientFilterSupport(serverFuncions); - } - return this.filterSupport; - } - - private List getServerSupportedFunctions() { - try { - ReactiveCatalogClient client = client(); - Flux functionNames = client.getSupportedFilterFunctionNames(); - List list = functionNames.toStream().toList(); - return list; - } catch (Exception e) { - log.warn( - "Error getting server-side supported filter function names. Won't use functions.", - e); - return Collections.emptyList(); - } - } - - @Override - public Optional findById(@NonNull String id, @NonNull Class clazz) { - ClassMappings typeArg = typeEnum(clazz); - - Optional ret = blockAndReturn(client.findById(endpoint(), id, typeArg)); - return ret; - } - - @Override - public void dispose() { - // no-op...? - } - - @Override - public void syncTo(@NonNull CatalogInfoRepository target) { - findAll().forEach(target::add); - } - - protected @NonNull ClassMappings typeEnum(@NonNull Class infoType) { - ClassMappings enumVal = ClassMappings.fromInterface(infoType); - if (enumVal == null) { - enumVal = ClassMappings.fromImpl(infoType); - } - return enumVal; - } -} diff --git a/src/catalog/catalog-server/client/src/main/java/org/geoserver/cloud/catalog/client/repository/CatalogClientRepositoryConfiguration.java b/src/catalog/catalog-server/client/src/main/java/org/geoserver/cloud/catalog/client/repository/CatalogClientRepositoryConfiguration.java deleted file mode 100644 index b024287d5..000000000 --- a/src/catalog/catalog-server/client/src/main/java/org/geoserver/cloud/catalog/client/repository/CatalogClientRepositoryConfiguration.java +++ /dev/null @@ -1,55 +0,0 @@ -/* - * (c) 2020 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.cloud.catalog.client.repository; - -import org.geoserver.cloud.catalog.client.reactivefeign.ReactiveCatalogApiClientConfiguration; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.context.annotation.Import; - -@Configuration -@Import(ReactiveCatalogApiClientConfiguration.class) -public class CatalogClientRepositoryConfiguration { - - @Bean - CatalogClientWorkspaceRepository cloudWorkspaceRepository() { - return new CatalogClientWorkspaceRepository(); - } - - @Bean - CatalogClientNamespaceRepository cloudNamespaceRepository() { - return new CatalogClientNamespaceRepository(); - } - - @Bean - CatalogClientStoreRepository cloudStoreRepository() { - return new CatalogClientStoreRepository(); - } - - @Bean - CatalogClientResourceRepository cloudResourceRepository() { - return new CatalogClientResourceRepository(); - } - - @Bean - CatalogClientLayerRepository cloudLayerRepository() { - return new CatalogClientLayerRepository(); - } - - @Bean - CatalogClientLayerGroupRepository cloudLayerGroupRepository() { - return new CatalogClientLayerGroupRepository(); - } - - @Bean - CatalogClientStyleRepository cloudStyleRepository() { - return new CatalogClientStyleRepository(); - } - - @Bean - CatalogClientMapRepository cloudMapRepository() { - return new CatalogClientMapRepository(); - } -} diff --git a/src/catalog/catalog-server/client/src/main/java/org/geoserver/cloud/catalog/client/repository/CatalogClientResourceRepository.java b/src/catalog/catalog-server/client/src/main/java/org/geoserver/cloud/catalog/client/repository/CatalogClientResourceRepository.java deleted file mode 100644 index 56c34d702..000000000 --- a/src/catalog/catalog-server/client/src/main/java/org/geoserver/cloud/catalog/client/repository/CatalogClientResourceRepository.java +++ /dev/null @@ -1,79 +0,0 @@ -/* - * (c) 2020 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.cloud.catalog.client.repository; - -import lombok.Getter; -import lombok.NonNull; - -import org.geoserver.catalog.NamespaceInfo; -import org.geoserver.catalog.ResourceInfo; -import org.geoserver.catalog.StoreInfo; -import org.geoserver.catalog.impl.ClassMappings; -import org.geoserver.catalog.plugin.CatalogInfoRepository.ResourceRepository; -import org.geoserver.catalog.plugin.Query; -import org.geotools.api.filter.Filter; -import org.geotools.api.filter.FilterFactory; -import org.geotools.factory.CommonFactoryFinder; -import org.springframework.lang.Nullable; - -import java.util.Optional; -import java.util.stream.Stream; - -public class CatalogClientResourceRepository extends CatalogClientRepository - implements ResourceRepository { - - private final @Getter Class contentType = ResourceInfo.class; - - // REVISIT: used to build filters on methods that miss a counterpart on ReactiveCatalogClient - private final FilterFactory ff = CommonFactoryFinder.getFilterFactory(); - - @Override - public Stream findAllByType(@Nullable Class clazz) { - return toStream(client().findAll(endpoint(), typeEnum(clazz)).map(clazz::cast)); - } - - @Override - public Stream findAllByNamespace( - @NonNull NamespaceInfo ns, @Nullable Class clazz) { - - // REVISIT: missed custom method on ReactiveCatalogClient - Filter filter = ff.equals(ff.property("namespace.id"), ff.literal(ns.getId())); - Query query = Query.valueOf(clazz, filter); - return findAll(query); - } - - @Override - public @Nullable Optional findByStoreAndName( - @NonNull StoreInfo store, @NonNull String name, @Nullable Class clazz) { - // REVISIT: missed custom method on ReactiveCatalogClient - Filter filter = - ff.and( - ff.equals(ff.property("store.id"), ff.literal(store.getId())), - ff.equals(ff.property("name"), ff.literal(name))); - - Query query = Query.valueOf(clazz, filter).setCount(1); - try (Stream flux = findAll(query)) { - return flux.findFirst(); - } - } - - @Override - public Stream findAllByStore(StoreInfo store, Class clazz) { - - // REVISIT: missed custom method on ReactiveCatalogClient - Filter filter = ff.equals(ff.property("store.id"), ff.literal(store.getId())); - Query query = Query.valueOf(clazz, filter); - return findAll(query); - } - - @Override - public Optional findByNameAndNamespace( - @NonNull String name, @NonNull NamespaceInfo namespace, @NonNull Class clazz) { - - String namespaceId = namespace.getId(); - ClassMappings type = typeEnum(clazz); - return blockAndReturn(client().findResourceByNamespaceIdAndName(namespaceId, name, type)); - } -} diff --git a/src/catalog/catalog-server/client/src/main/java/org/geoserver/cloud/catalog/client/repository/CatalogClientStoreRepository.java b/src/catalog/catalog-server/client/src/main/java/org/geoserver/cloud/catalog/client/repository/CatalogClientStoreRepository.java deleted file mode 100644 index 7d01c0de2..000000000 --- a/src/catalog/catalog-server/client/src/main/java/org/geoserver/cloud/catalog/client/repository/CatalogClientStoreRepository.java +++ /dev/null @@ -1,78 +0,0 @@ -/* - * (c) 2020 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.cloud.catalog.client.repository; - -import lombok.Getter; -import lombok.NonNull; - -import org.geoserver.catalog.DataStoreInfo; -import org.geoserver.catalog.StoreInfo; -import org.geoserver.catalog.WorkspaceInfo; -import org.geoserver.catalog.impl.ClassMappings; -import org.geoserver.catalog.plugin.CatalogInfoRepository.StoreRepository; -import org.springframework.lang.Nullable; - -import reactor.core.publisher.Flux; - -import java.util.Optional; -import java.util.stream.Stream; - -public class CatalogClientStoreRepository extends CatalogClientRepository - implements StoreRepository { - - private final @Getter Class contentType = StoreInfo.class; - - @Override - public void setDefaultDataStore( - @NonNull WorkspaceInfo workspace, @NonNull DataStoreInfo dataStore) { - - String workspaceId = workspace.getId(); - String dataStoreId = dataStore.getId(); - blockAndReturn(client().setDefaultDataStoreByWorkspaceId(workspaceId, dataStoreId)); - } - - @Override - public void unsetDefaultDataStore(@NonNull WorkspaceInfo workspace) { - String workspaceId = workspace.getId(); - blockAndReturn(client().unsetDefaultDataStore(workspaceId)); - } - - @Override - public Optional getDefaultDataStore(@NonNull WorkspaceInfo workspace) { - String workspaceId = workspace.getId(); - return blockAndReturn(client().findDefaultDataStoreByWorkspaceId(workspaceId)); - } - - @Override - public Stream getDefaultDataStores() { - return toStream(client().getDefaultDataStores()); - } - - @Override - public Stream findAllByWorkspace( - @NonNull WorkspaceInfo workspace, @Nullable Class clazz) { - - String workspaceId = workspace.getId(); - ClassMappings type = typeEnum(clazz); - - Flux flux = client().findStoresByWorkspaceId(workspaceId, type); - return toStream(flux); - } - - @Override - public Stream findAllByType(@NonNull Class clazz) { - - return toStream(client().findAll(endpoint(), typeEnum(clazz)).map(clazz::cast)); - } - - @Override - public Optional findByNameAndWorkspace( - @NonNull String name, @NonNull WorkspaceInfo workspace, @NonNull Class clazz) { - - String workspaceId = workspace.getId(); - ClassMappings type = typeEnum(clazz); - return blockAndReturn(client().findStoreByWorkspaceIdAndName(workspaceId, name, type)); - } -} diff --git a/src/catalog/catalog-server/client/src/main/java/org/geoserver/cloud/catalog/client/repository/CatalogClientStyleRepository.java b/src/catalog/catalog-server/client/src/main/java/org/geoserver/cloud/catalog/client/repository/CatalogClientStyleRepository.java deleted file mode 100644 index c858c316c..000000000 --- a/src/catalog/catalog-server/client/src/main/java/org/geoserver/cloud/catalog/client/repository/CatalogClientStyleRepository.java +++ /dev/null @@ -1,44 +0,0 @@ -/* - * (c) 2020 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.cloud.catalog.client.repository; - -import lombok.Getter; -import lombok.NonNull; - -import org.geoserver.catalog.StyleInfo; -import org.geoserver.catalog.WorkspaceInfo; -import org.geoserver.catalog.plugin.CatalogInfoRepository.StyleRepository; - -import java.util.Optional; -import java.util.stream.Stream; - -public class CatalogClientStyleRepository extends CatalogClientRepository - implements StyleRepository { - - private final @Getter Class contentType = StyleInfo.class; - - @Override - public Stream findAllByNullWorkspace() { - return toStream(client().findStylesByNullWorkspace()); - } - - @Override - public Stream findAllByWorkspace(@NonNull WorkspaceInfo ws) { - return toStream(client().findStylesByWorkspaceId(ws.getId())); - } - - @Override - public Optional findByNameAndWordkspaceNull(@NonNull String name) { - return blockAndReturn(client().findStyleByNameAndNullWorkspace(name)); - } - - @Override - public Optional findByNameAndWorkspace( - @NonNull String name, @NonNull WorkspaceInfo workspace) { - - String workspaceId = workspace.getId(); - return blockAndReturn(client().findStyleByWorkspaceIdAndName(workspaceId, name)); - } -} diff --git a/src/catalog/catalog-server/client/src/main/java/org/geoserver/cloud/catalog/client/repository/CatalogClientWorkspaceRepository.java b/src/catalog/catalog-server/client/src/main/java/org/geoserver/cloud/catalog/client/repository/CatalogClientWorkspaceRepository.java deleted file mode 100644 index 88c2641e5..000000000 --- a/src/catalog/catalog-server/client/src/main/java/org/geoserver/cloud/catalog/client/repository/CatalogClientWorkspaceRepository.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * (c) 2020 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.cloud.catalog.client.repository; - -import lombok.Getter; -import lombok.NonNull; - -import org.geoserver.catalog.WorkspaceInfo; -import org.geoserver.catalog.plugin.CatalogInfoRepository.WorkspaceRepository; -import org.springframework.lang.Nullable; - -import java.util.Objects; -import java.util.Optional; - -public class CatalogClientWorkspaceRepository extends CatalogClientRepository - implements WorkspaceRepository { - - private final @Getter Class contentType = WorkspaceInfo.class; - - @Override - public void setDefaultWorkspace(@NonNull WorkspaceInfo workspace) { - Objects.requireNonNull(workspace.getId(), "workspace id can't be null"); - blockAndReturn(client().setDefaultWorkspace(workspace.getId())); - } - - @Override - public void unsetDefaultWorkspace() { - block(client().unsetDefaultWorkspace()); - } - - @Override - public @Nullable Optional getDefaultWorkspace() { - return blockAndReturn(client().getDefaultWorkspace()); - } -} diff --git a/src/catalog/catalog-server/client/src/test/java/org/geoserver/cloud/catalog/client/impl/CatalogClientConfigurationTest.java b/src/catalog/catalog-server/client/src/test/java/org/geoserver/cloud/catalog/client/impl/CatalogClientConfigurationTest.java deleted file mode 100644 index 9f3722fec..000000000 --- a/src/catalog/catalog-server/client/src/test/java/org/geoserver/cloud/catalog/client/impl/CatalogClientConfigurationTest.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * (c) 2020 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.cloud.catalog.client.impl; - -import static org.junit.jupiter.api.Assertions.assertNotNull; - -import org.geoserver.jackson.databind.catalog.GeoServerCatalogModule; -import org.geoserver.jackson.databind.config.GeoServerConfigModule; -import org.geotools.jackson.databind.filter.GeoToolsFilterModule; -import org.geotools.jackson.databind.geojson.GeoToolsGeoJsonModule; -import org.junit.jupiter.api.Test; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.autoconfigure.EnableAutoConfiguration; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.test.context.ActiveProfiles; - -@SpringBootTest(classes = CatalogClientConfiguration.class) -@EnableAutoConfiguration -@ActiveProfiles("test") -class CatalogClientConfigurationTest { - - private @Autowired CatalogClientCatalogFacade rawCatalogServiceFacade; - - private @Autowired GeoServerCatalogModule catalogJacksonModule; - private @Autowired GeoServerConfigModule configJacksonModule; - private @Autowired GeoToolsFilterModule geotoolsFilterModule; - private @Autowired GeoToolsGeoJsonModule geotoolsGeoJSONModule; - - @Test - void smokeTest() { - assertNotNull(rawCatalogServiceFacade); - assertNotNull(catalogJacksonModule); - assertNotNull(configJacksonModule); - assertNotNull(geotoolsFilterModule); - assertNotNull(geotoolsGeoJSONModule); - } -} diff --git a/src/catalog/catalog-server/client/src/test/java/org/geoserver/cloud/catalog/client/reactivefeign/ReactiveCatalogApiClientConfigurationTest.java b/src/catalog/catalog-server/client/src/test/java/org/geoserver/cloud/catalog/client/reactivefeign/ReactiveCatalogApiClientConfigurationTest.java deleted file mode 100644 index 9ca0b0b81..000000000 --- a/src/catalog/catalog-server/client/src/test/java/org/geoserver/cloud/catalog/client/reactivefeign/ReactiveCatalogApiClientConfigurationTest.java +++ /dev/null @@ -1,66 +0,0 @@ -/* - * (c) 2020 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.cloud.catalog.client.reactivefeign; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.junit.jupiter.api.Assertions.assertNotNull; - -import org.junit.jupiter.api.Test; -import org.springframework.boot.autoconfigure.AutoConfigurations; -import org.springframework.boot.autoconfigure.web.reactive.function.client.WebClientAutoConfiguration; -import org.springframework.boot.context.annotation.UserConfigurations; -import org.springframework.boot.test.context.runner.ApplicationContextRunner; -import org.springframework.cloud.openfeign.FeignAutoConfiguration; - -import reactivefeign.spring.config.ReactiveFeignAutoConfiguration; - -class ReactiveCatalogApiClientConfigurationTest { - - private final ApplicationContextRunner contextRunner = - new ApplicationContextRunner() // - .withAllowBeanDefinitionOverriding(true) - .withPropertyValues("reactive.feign.loadbalancer.enabled=false") - .withConfiguration( - AutoConfigurations.of( // - ReactiveFeignAutoConfiguration.class, // - FeignAutoConfiguration.class, // - WebClientAutoConfiguration.class // - )) - .withConfiguration( - UserConfigurations.of( // - ReactiveCatalogApiClientConfiguration.class // - )); - - @Test - void testReactiveCatalogClientIsLoaded() { - this.contextRunner.run( - context -> { - assertThat(context).hasSingleBean(ReactiveCatalogClient.class); - ReactiveCatalogClient client = context.getBean(ReactiveCatalogClient.class); - assertNotNull(client); - }); - } - - @Test - void testReactiveConfigClientIsLoaded() { - this.contextRunner.run( - context -> { - assertThat(context).hasSingleBean(ReactiveConfigClient.class); - ReactiveConfigClient client = context.getBean(ReactiveConfigClient.class); - assertNotNull(client); - }); - } - - @Test - void testReactiveResourceStoreClientIsLoaded() { - this.contextRunner.run( - context -> { - assertThat(context).hasSingleBean(ReactiveResourceStoreClient.class); - ReactiveResourceStoreClient client = - context.getBean(ReactiveResourceStoreClient.class); - assertNotNull(client); - }); - } -} diff --git a/src/catalog/catalog-server/client/src/test/java/org/geoserver/cloud/catalog/client/repository/CatalogClientRepositoryConfigurationTest.java b/src/catalog/catalog-server/client/src/test/java/org/geoserver/cloud/catalog/client/repository/CatalogClientRepositoryConfigurationTest.java deleted file mode 100644 index fb9fa37e2..000000000 --- a/src/catalog/catalog-server/client/src/test/java/org/geoserver/cloud/catalog/client/repository/CatalogClientRepositoryConfigurationTest.java +++ /dev/null @@ -1,88 +0,0 @@ -/* - * (c) 2020 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.cloud.catalog.client.repository; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.junit.jupiter.api.Assertions.assertNotNull; - -import org.geoserver.cloud.catalog.client.reactivefeign.ReactiveCatalogApiClientConfiguration; -import org.geoserver.cloud.catalog.client.reactivefeign.ReactiveCatalogClient; -import org.junit.jupiter.api.Test; -import org.springframework.boot.autoconfigure.AutoConfigurations; -import org.springframework.boot.autoconfigure.web.reactive.function.client.WebClientAutoConfiguration; -import org.springframework.boot.context.annotation.UserConfigurations; -import org.springframework.boot.test.context.runner.ApplicationContextRunner; - -import reactivefeign.spring.config.ReactiveFeignAutoConfiguration; - -class CatalogClientRepositoryConfigurationTest { - - private final ApplicationContextRunner contextRunner = - new ApplicationContextRunner() - .withAllowBeanDefinitionOverriding(true) - .withPropertyValues("reactive.feign.loadbalancer.enabled=false") - .withConfiguration( - AutoConfigurations.of( - ReactiveFeignAutoConfiguration.class, - WebClientAutoConfiguration.class)) - .withConfiguration( - UserConfigurations.of( - ReactiveCatalogApiClientConfiguration.class, - CatalogClientRepositoryConfiguration.class)); - - void verify(Class> repoType) { - this.contextRunner.run(context -> assertThat(context).hasSingleBean(repoType)); - - this.contextRunner.run( - context -> - assertThat(context) - .getBean(repoType) - .satisfies( - r -> { - ReactiveCatalogClient client = r.client(); - assertNotNull(client); - })); - } - - @Test - void workspaceRepository() { - verify(CatalogClientWorkspaceRepository.class); - } - - @Test - void namespaceRepository() { - verify(CatalogClientNamespaceRepository.class); - } - - @Test - void storeRepository() { - verify(CatalogClientStoreRepository.class); - } - - @Test - void resourceRepository() { - verify(CatalogClientResourceRepository.class); - } - - @Test - void layerRepository() { - verify(CatalogClientLayerRepository.class); - } - - @Test - void layerGroupRepository() { - verify(CatalogClientLayerGroupRepository.class); - } - - @Test - void styleRepository() { - verify(CatalogClientNamespaceRepository.class); - } - - @Test - void mapRepository() { - verify(CatalogClientMapRepository.class); - } -} diff --git a/src/catalog/catalog-server/client/src/test/java/org/geoserver/cloud/catalog/client/repository/CatalogClientRepositoryTest.java b/src/catalog/catalog-server/client/src/test/java/org/geoserver/cloud/catalog/client/repository/CatalogClientRepositoryTest.java deleted file mode 100644 index be2776a8e..000000000 --- a/src/catalog/catalog-server/client/src/test/java/org/geoserver/cloud/catalog/client/repository/CatalogClientRepositoryTest.java +++ /dev/null @@ -1,365 +0,0 @@ -/* - * (c) 2020 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.cloud.catalog.client.repository; - -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.equalTo; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertNotNull; -import static org.junit.jupiter.api.Assertions.assertSame; -import static org.junit.jupiter.api.Assertions.assertThrows; -import static org.junit.jupiter.api.Assertions.assertTrue; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.ArgumentMatchers.same; -import static org.mockito.Mockito.atMostOnce; -import static org.mockito.Mockito.clearInvocations; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.verifyNoMoreInteractions; -import static org.mockito.Mockito.when; - -import lombok.NonNull; - -import org.geoserver.catalog.Catalog; -import org.geoserver.catalog.CatalogInfo; -import org.geoserver.catalog.CatalogTestData; -import org.geoserver.catalog.DataStoreInfo; -import org.geoserver.catalog.WorkspaceInfo; -import org.geoserver.catalog.impl.ClassMappings; -import org.geoserver.catalog.plugin.CatalogInfoRepository; -import org.geoserver.catalog.plugin.CatalogInfoRepository.LayerGroupRepository; -import org.geoserver.catalog.plugin.CatalogInfoRepository.LayerRepository; -import org.geoserver.catalog.plugin.CatalogInfoRepository.NamespaceRepository; -import org.geoserver.catalog.plugin.CatalogInfoRepository.ResourceRepository; -import org.geoserver.catalog.plugin.CatalogInfoRepository.StoreRepository; -import org.geoserver.catalog.plugin.CatalogInfoRepository.StyleRepository; -import org.geoserver.catalog.plugin.CatalogInfoRepository.WorkspaceRepository; -import org.geoserver.catalog.plugin.CatalogPlugin; -import org.geoserver.catalog.plugin.Patch; -import org.geoserver.catalog.plugin.Query; -import org.geoserver.cloud.catalog.client.reactivefeign.ReactiveCatalogClient; -import org.geoserver.function.IsInstanceOf; -import org.geoserver.ows.util.OwsUtils; -import org.geotools.api.filter.Filter; -import org.geotools.api.filter.capability.FunctionName; -import org.geotools.filter.function.FilterFunction_toWKT; -import org.geotools.filter.function.math.FilterFunction_abs; -import org.geotools.filter.function.math.FilterFunction_acos; -import org.geotools.filter.text.cql2.CQLException; -import org.geotools.filter.text.ecql.ECQL; -import org.junit.jupiter.api.AfterEach; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.boot.test.mock.mockito.MockBean; -import org.springframework.test.context.ActiveProfiles; - -import reactor.core.publisher.Flux; -import reactor.core.publisher.Mono; - -import java.util.Arrays; -import java.util.List; -import java.util.Optional; - -@SpringBootTest(classes = CatalogClientRepositoryConfiguration.class) -@ActiveProfiles("test") -class CatalogClientRepositoryTest { - - private @MockBean ReactiveCatalogClient mockClient; - - private @Autowired WorkspaceRepository workspaceRepository; - private @Autowired NamespaceRepository namespaceRepository; - private @Autowired StoreRepository storeRepository; - private @Autowired ResourceRepository resourceRepository; - private @Autowired LayerRepository layerRepository; - private @Autowired LayerGroupRepository layerGroupRepository; - private @Autowired StyleRepository styleRepository; - - private static final Catalog fakeCatalog = new CatalogPlugin(); - protected CatalogTestData testData; - - public @BeforeEach void before() { - List functions = - Arrays.asList( - IsInstanceOf.NAME, - FilterFunction_abs.NAME, - FilterFunction_acos.NAME, - FilterFunction_toWKT.NAME); - when(mockClient.getSupportedFilterFunctionNames()).thenReturn(Flux.fromIterable(functions)); - testData = - CatalogTestData.empty(() -> fakeCatalog, () -> null).initConfig(false).initialize(); - } - - public @AfterEach void after() { - testData.after(); - } - - @Test - void workspaceRepository_CRUD() { - crudTest(workspaceRepository, testData.workspaceA); - } - - @Test - void workspaceRepository_DefaultWorkspace() { - - when(mockClient.getDefaultWorkspace()).thenReturn(Mono.just(testData.workspaceB)); - assertSame(testData.workspaceB, workspaceRepository.getDefaultWorkspace().get()); - verify(mockClient, times(1)).getDefaultWorkspace(); - - when(mockClient.setDefaultWorkspace(eq(testData.workspaceA.getId()))) - .thenReturn(Mono.just(testData.workspaceA)); - workspaceRepository.setDefaultWorkspace(testData.workspaceA); - verify(mockClient, times(1)).setDefaultWorkspace(eq(testData.workspaceA.getId())); - - verifyNoMoreInteractions(mockClient); - assertThrows( - NullPointerException.class, () -> workspaceRepository.setDefaultWorkspace(null)); - } - - @Test - void namespaceRepository_CRUD() { - crudTest(namespaceRepository, testData.namespaceA); - } - - @Test - void namespaceRepository_DefaultNamespace() { - when(mockClient.getDefaultNamespace()).thenReturn(Mono.just(testData.namespaceB)); - assertSame(testData.namespaceB, namespaceRepository.getDefaultNamespace().get()); - verify(mockClient, times(1)).getDefaultNamespace(); - - when(mockClient.setDefaultNamespace(eq(testData.namespaceA.getId()))) - .thenReturn(Mono.just(testData.namespaceA)); - namespaceRepository.setDefaultNamespace(testData.namespaceA); - verify(mockClient, times(1)).setDefaultNamespace(eq(testData.namespaceA.getId())); - - verifyNoMoreInteractions(mockClient); - assertThrows( - NullPointerException.class, () -> namespaceRepository.setDefaultNamespace(null)); - } - - @Test - void storeRepository_CRUD() { - crudTest(storeRepository, testData.coverageStoreA); - crudTest(storeRepository, testData.dataStoreA); - crudTest(storeRepository, testData.wmsStoreA); - crudTest(storeRepository, testData.wmtsStoreA); - } - - @Test - void storeRepository_GetDefaultDataStore() { - when(mockClient.findDefaultDataStoreByWorkspaceId(eq(testData.workspaceA.getId()))) - .thenReturn(Mono.just(testData.dataStoreA)); - when(mockClient.findDefaultDataStoreByWorkspaceId(eq(testData.workspaceB.getId()))) - .thenReturn(Mono.just(testData.dataStoreB)); - - assertSame( - testData.dataStoreA, - storeRepository.getDefaultDataStore(testData.workspaceA).get()); - assertSame( - testData.dataStoreB, - storeRepository.getDefaultDataStore(testData.workspaceB).get()); - assertThrows(NullPointerException.class, () -> storeRepository.getDefaultDataStore(null)); - } - - @Test - void storeRepository_SetDefaultDataStore() { - - WorkspaceInfo newWs = testData.workspaceC; - DataStoreInfo ds = testData.dataStoreA; - - when(mockClient.setDefaultDataStoreByWorkspaceId(eq(newWs.getId()), eq(ds.getId()))) - .thenReturn(Mono.just(ds)); - - storeRepository.setDefaultDataStore(newWs, ds); - verify(mockClient, times(1)) - .setDefaultDataStoreByWorkspaceId(eq(newWs.getId()), eq(ds.getId())); - assertThrows( - NullPointerException.class, () -> storeRepository.setDefaultDataStore(null, ds)); - assertThrows( - NullPointerException.class, () -> storeRepository.setDefaultDataStore(newWs, null)); - verifyNoMoreInteractions(mockClient); - } - - @Test - void storeRepository_GetDefaultDataStores_Empty() { - when(mockClient.getDefaultDataStores()).thenReturn(Flux.empty()); - assertEquals(0L, storeRepository.getDefaultDataStores().count()); - verify(mockClient, times(1)).getDefaultDataStores(); - verifyNoMoreInteractions(mockClient); - } - - @Test - void storeRepository_GetDefaultDataStores() { - when(mockClient.getDefaultDataStores()) - .thenReturn(Flux.just(testData.dataStoreA, testData.dataStoreB)); - assertEquals(2L, storeRepository.getDefaultDataStores().count()); - verify(mockClient, times(1)).getDefaultDataStores(); - verifyNoMoreInteractions(mockClient); - } - - @Test - void resourceRepository_CRUD() { - crudTest(resourceRepository, testData.coverageA); - crudTest(resourceRepository, testData.featureTypeA); - crudTest(resourceRepository, testData.wmsLayerA); - crudTest(resourceRepository, testData.wmtsLayerA); - } - - @Test - void layerRepository_CRUD() { - crudTest(layerRepository, testData.layerFeatureTypeA); - } - - @Test - void layerGroupRepository_CRUD() { - crudTest(layerGroupRepository, testData.layerGroup1); - } - - @Test - void styleRepository_CRUD() { - crudTest(styleRepository, testData.style1); - } - - private void crudTest(CatalogInfoRepository repo, T info) { - - assertCreate(repo, info); - - assertFindById(repo, info); - assertFindByName(repo, info); - assertFindAll(repo, info); - - assertUpdate(repo, info); - - assertDelete(repo, info); - - verify(mockClient, atMostOnce()).getSupportedFilterFunctionNames(); - verifyNoMoreInteractions(mockClient); - clearInvocations(mockClient); - } - - private void assertDelete(CatalogInfoRepository repo, T info) { - when(mockClient.deleteById(any(String.class), eq(info.getId()))) - .thenReturn(Mono.just(info)); - repo.remove(info); - verify(mockClient, times(1)).deleteById(any(String.class), eq(info.getId())); - } - - private void assertUpdate(CatalogInfoRepository repo, T info) { - Patch patch = new Patch(); - patch.add(new Patch.Property("name", "newName")); - - when(mockClient.update(any(String.class), eq(info.getId()), eq(patch))) - .thenReturn(Mono.just(info)); - repo.update(info, patch); - verify(mockClient, times(1)).update(any(String.class), eq(info.getId()), eq(patch)); - } - - private void assertCreate(CatalogInfoRepository repo, T info) { - when(mockClient.create(any(String.class), same(info))).thenReturn(Mono.just(info)); - repo.add(info); - verify(mockClient, times(1)).create(any(String.class), same(info)); - } - - private void assertFindById(CatalogInfoRepository repo, T info) { - @SuppressWarnings("unchecked") - Class clazz = (Class) info.getClass(); - ClassMappings expectedEnumType = ClassMappings.fromImpl(clazz); - assertNotNull(expectedEnumType); - - final String id = info.getId(); - when(mockClient.findById(any(String.class), eq(id), eq(expectedEnumType))) - .thenReturn(Mono.just(info)); - Optional retrieved = repo.findById(id, clazz); - assertTrue(retrieved.isPresent()); - assertSame(info, retrieved.get()); - verify(mockClient, times(1)).findById(any(String.class), eq(id), eq(expectedEnumType)); - } - - private void assertFindByName(CatalogInfoRepository repo, T info) { - - final @NonNull String name = simpleName(info); - final @NonNull ClassMappings subType = ClassMappings.fromImpl(info.getClass()); - @SuppressWarnings("unchecked") - Class type = (Class) subType.getInterface(); - - when(mockClient.findFirstByName(any(String.class), eq(name), eq(subType))) - .thenReturn(Mono.just(info)); - - Optional found = repo.findFirstByName(name, type); - assertTrue(found.isPresent()); - assertSame(info, found.get()); - verify(mockClient, times(1)).findFirstByName(any(String.class), eq(name), eq(subType)); - } - - @Test - void testFindByNameNullType() { - testFindByNameNullType(workspaceRepository, testData.workspaceA.getName()); - testFindByNameNullType(namespaceRepository, testData.namespaceA.getName()); - testFindByNameNullType(storeRepository, testData.dataStoreA.getName()); - testFindByNameNullType(resourceRepository, testData.coverageA.getName()); - testFindByNameNullType(layerRepository, testData.layerFeatureTypeA.getName()); - testFindByNameNullType(layerGroupRepository, testData.layerGroup1.getName()); - testFindByNameNullType(styleRepository, testData.style1.getName()); - } - - private void testFindByNameNullType( - @NonNull CatalogInfoRepository repo, @NonNull String name) { - assertThrows(NullPointerException.class, () -> repo.findFirstByName(name, null)); - } - - private @NonNull String simpleName(CatalogInfo info) { - return (@NonNull String) OwsUtils.get(info, "name"); - } - - private void assertFindAll(CatalogInfoRepository repo, T info) { - - final @NonNull ClassMappings genericType = genericType(info); - - when(mockClient.findAll(any(String.class), same(genericType))) - .thenReturn(Flux.just(info, info)); - assertThat(repo.findAll().count(), equalTo(2L)); - verify(mockClient, times(1)).findAll(any(String.class), same(genericType)); - - Query query = Query.all(genericType.getInterface()); - - when(mockClient.query(any(String.class), same(query))).thenReturn(Flux.just(info)); - assertThat(repo.findAll(query).count(), equalTo(1L)); - verify(mockClient, times(1)).query(any(String.class), same(query)); - - final @NonNull ClassMappings subType = ClassMappings.fromImpl(info.getClass()); - Filter someFilter; - try { - someFilter = ECQL.toFilter("name = 'test'"); - } catch (CQLException e) { - throw new RuntimeException(); - } - @SuppressWarnings("unchecked") - Class type = (Class) subType.getInterface(); - query = Query.valueOf(type, someFilter); - when(mockClient.query(any(String.class), same(query))).thenReturn(Flux.just(info)); - assertThat(repo.findAll(query).count(), equalTo(1L)); - verify(mockClient, times(1)).query(any(String.class), same(query)); - } - - private @NonNull ClassMappings genericType(CatalogInfo info) { - ClassMappings type = ClassMappings.fromImpl(info.getClass()); - switch (type) { - case COVERAGESTORE: - case DATASTORE: - case WMSSTORE: - case WMTSSTORE: - return ClassMappings.STORE; - case COVERAGE: - case FEATURETYPE: - case WMSLAYER: - case WMTSLAYER: - return ClassMappings.RESOURCE; - default: - return type; - } - } -} diff --git a/src/catalog/catalog-server/client/src/test/resources/application-test.yml b/src/catalog/catalog-server/client/src/test/resources/application-test.yml deleted file mode 100644 index 75e8fb318..000000000 --- a/src/catalog/catalog-server/client/src/test/resources/application-test.yml +++ /dev/null @@ -1,49 +0,0 @@ -spring: - main: - banner-mode: off - allow-bean-definition-overriding: true - allow-circular-references: true # false by default since spring-boot 2.6.0, breaks geoserver initialization - cloud.config.enabled: false - cloud.config.discovery.enabled: false - cloud.bus.enabled: false -eureka.client.enabled: false - -feign: - logger.level: full - client: - config: - catalog-service: - connectTimeout: 5000 - readTimeout: 5000 - loggerLevel: full - decode404: true - -geoserver: - security.enabled: false - catalog: - isolated: true - advertised: true - localWorkspace: true - secure: true - backend: - data-directory: - enabled: false - location: ${java.io.tmpdir}/gscloud_tests/data_directory_${random.uuid} - jdbcconfig: - enabled: false - initdb: true - cache-directory: ${java.io.tmpdir}/gscloud_tests/jdbcconfig_cache_${random.uuid} - datasource: - driverClassname: org.h2.Driver - url: jdbc:h2:mem:test; - username: sa - password: - -logging: - level: - root: WARN - org.geoserver.platform: ERROR - org.geoserver.cloud: DEBUG - org.geoserver.cloud.config.factory: TRACE - org.springframework.test: ERROR - diff --git a/src/catalog/catalog-server/pom.xml b/src/catalog/catalog-server/pom.xml deleted file mode 100644 index b7d8d703d..000000000 --- a/src/catalog/catalog-server/pom.xml +++ /dev/null @@ -1,17 +0,0 @@ - - - 4.0.0 - - org.geoserver.cloud.catalog - gs-cloud-catalog - ${revision} - - org.geoserver.cloud.catalog.service - gs-cloud-catalog-server - pom - Reactive Catalog Server and Client Libraries - - client - server - - diff --git a/src/catalog/catalog-server/server/README.md b/src/catalog/catalog-server/server/README.md deleted file mode 100644 index 6d821a9ee..000000000 --- a/src/catalog/catalog-server/server/README.md +++ /dev/null @@ -1,7 +0,0 @@ -# Cloud Native GeoServer Catalog service - -Spring Webflux reactive microservice that exposes the GeoServer *catalog*, *global*, and *resources* configuration -objects through a RESTful API to other microservices, in order to abstract out the microservices that require access -to the catalog from the actual catalog backend and implementation. - -Follow the service [documentation](../../../docs/develop/services/catalog-service.md) and keep it up to date . diff --git a/src/catalog/catalog-server/server/pom.xml b/src/catalog/catalog-server/server/pom.xml deleted file mode 100644 index 14013e300..000000000 --- a/src/catalog/catalog-server/server/pom.xml +++ /dev/null @@ -1,34 +0,0 @@ - - - 4.0.0 - - org.geoserver.cloud.catalog.service - gs-cloud-catalog-server - ${revision} - - gs-cloud-reactive-catalog-server - jar - Reactive catalog-Service server library - - - org.geoserver.cloud - gs-cloud-starter-reactive - - - org.geoserver.cloud.catalog.jackson - gs-cloud-starter-jackson - - - org.geoserver.cloud.catalog - gs-cloud-catalog-plugin - ${project.version} - test-jar - test - - - org.springframework.boot - spring-boot-configuration-processor - true - - - diff --git a/src/catalog/catalog-server/server/src/main/java/org/geoserver/cloud/autoconfigure/catalog/server/CatalogServerAutoConfiguration.java b/src/catalog/catalog-server/server/src/main/java/org/geoserver/cloud/autoconfigure/catalog/server/CatalogServerAutoConfiguration.java deleted file mode 100644 index 431e412c7..000000000 --- a/src/catalog/catalog-server/server/src/main/java/org/geoserver/cloud/autoconfigure/catalog/server/CatalogServerAutoConfiguration.java +++ /dev/null @@ -1,16 +0,0 @@ -/* - * (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.cloud.autoconfigure.catalog.server; - -import org.geoserver.cloud.catalog.server.config.CatalogServerConfiguration; -import org.springframework.context.annotation.Configuration; -import org.springframework.context.annotation.Import; - -/** - * @since 1.0 - */ -@Configuration(proxyBeanMethods = false) -@Import(CatalogServerConfiguration.class) -public class CatalogServerAutoConfiguration {} diff --git a/src/catalog/catalog-server/server/src/main/java/org/geoserver/cloud/catalog/server/api/v1/ApiExceptionHandler.java b/src/catalog/catalog-server/server/src/main/java/org/geoserver/cloud/catalog/server/api/v1/ApiExceptionHandler.java deleted file mode 100644 index 8ba25f45c..000000000 --- a/src/catalog/catalog-server/server/src/main/java/org/geoserver/cloud/catalog/server/api/v1/ApiExceptionHandler.java +++ /dev/null @@ -1,27 +0,0 @@ -/* - * (c) 2020 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.cloud.catalog.server.api.v1; - -import org.springframework.http.HttpStatus; -import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.ExceptionHandler; -import org.springframework.web.bind.annotation.RestControllerAdvice; -import org.springframework.web.server.ResponseStatusException; - -import java.util.NoSuchElementException; - -@RestControllerAdvice -public class ApiExceptionHandler { - - @ExceptionHandler(IllegalArgumentException.class) - public ResponseEntity illegalArgumentException(IllegalArgumentException e) { - throw new ResponseStatusException(HttpStatus.BAD_REQUEST, e.getMessage(), e); - } - - @ExceptionHandler(NoSuchElementException.class) - public ResponseEntity noSuchElementException(NoSuchElementException e) { - throw new ResponseStatusException(HttpStatus.NO_CONTENT, e.getMessage(), e); - } -} diff --git a/src/catalog/catalog-server/server/src/main/java/org/geoserver/cloud/catalog/server/api/v1/ReactiveCatalogController.java b/src/catalog/catalog-server/server/src/main/java/org/geoserver/cloud/catalog/server/api/v1/ReactiveCatalogController.java deleted file mode 100644 index f46654d04..000000000 --- a/src/catalog/catalog-server/server/src/main/java/org/geoserver/cloud/catalog/server/api/v1/ReactiveCatalogController.java +++ /dev/null @@ -1,446 +0,0 @@ -/* - * (c) 2020 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.cloud.catalog.server.api.v1; - -import static org.geoserver.catalog.impl.ClassMappings.RESOURCE; -import static org.geoserver.catalog.impl.ClassMappings.STORE; -import static org.springframework.http.MediaType.APPLICATION_STREAM_JSON_VALUE; - -import lombok.NonNull; - -import org.geoserver.catalog.CatalogFacade; -import org.geoserver.catalog.CatalogInfo; -import org.geoserver.catalog.DataStoreInfo; -import org.geoserver.catalog.LayerGroupInfo; -import org.geoserver.catalog.LayerInfo; -import org.geoserver.catalog.NamespaceInfo; -import org.geoserver.catalog.ResourceInfo; -import org.geoserver.catalog.StoreInfo; -import org.geoserver.catalog.StyleInfo; -import org.geoserver.catalog.WorkspaceInfo; -import org.geoserver.catalog.impl.ClassMappings; -import org.geoserver.catalog.plugin.Patch; -import org.geoserver.catalog.plugin.Query; -import org.geoserver.cloud.catalog.server.service.ProxyResolver; -import org.geoserver.cloud.catalog.server.service.ReactiveCatalog; -import org.geotools.api.filter.capability.FunctionName; -import org.springframework.http.HttpStatus; -import org.springframework.web.bind.annotation.DeleteMapping; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PatchMapping; -import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.PutMapping; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestParam; -import org.springframework.web.bind.annotation.ResponseStatus; -import org.springframework.web.bind.annotation.RestController; -import org.springframework.web.server.ResponseStatusException; - -import reactor.core.publisher.Flux; -import reactor.core.publisher.Mono; - -/** */ -@RestController -@RequestMapping(path = ReactiveCatalogController.BASE_URI) -public class ReactiveCatalogController { - - public static final String BASE_URI = "/api/v1/catalog"; - - private ReactiveCatalog catalog; - - private ProxyResolver proxyResolver; - - public ReactiveCatalogController(ReactiveCatalog catalog, ProxyResolver proxyResolver) { - this.catalog = catalog; - this.proxyResolver = proxyResolver; - } - - @PostMapping(path = "/{endpoint}") - @ResponseStatus(HttpStatus.CREATED) - public Mono create( - @PathVariable("endpoint") String endpoint, @RequestBody C info) { - - return catalog.create(Mono.just(info).flatMap(proxyResolver::resolve)); - } - - @PatchMapping(path = "/{endpoint}/{id}") - public Mono update( - @PathVariable("endpoint") String endpoint, - @PathVariable("id") String id, - @RequestBody Patch patch) { - - Mono resolvedPatch = proxyResolver.resolve(patch); - - Class type = endpointToClass(endpoint); - - Mono object = - catalog.getById(id, type) - .switchIfEmpty( - noContent( - "%s with id '%s' does not exist", - type.getSimpleName(), id)); - - try { - return object.flatMap(c -> catalog.update(c, resolvedPatch)); - } catch (RuntimeException e) { - e.printStackTrace(); - throw e; - } - } - - @DeleteMapping(path = "/{endpoint}") - public Mono delete( - @PathVariable("endpoint") String endpoint, @NonNull C value) { - - ClassMappings type = endpointToType(endpoint); - return catalog.delete(value) - .switchIfEmpty( - noContent( - "%s with id '%s' does not exist", - type.getInterface().getSimpleName(), value.getId())); - } - - @DeleteMapping(path = "/{endpoint}/{id}") - public Mono deleteById( - @PathVariable("endpoint") String endpoint, @PathVariable("id") String id) { - Class type = endpointToClass(endpoint, null); - return catalog.getById(id, type) - .flatMap(i -> catalog.delete(i)) - .switchIfEmpty( - noContent("%s with id '%s' does not exist", type.getSimpleName(), id)); - } - - @GetMapping(path = "/{endpoint}", produces = APPLICATION_STREAM_JSON_VALUE) - public Flux findAll( - @PathVariable("endpoint") String endpoint, - @RequestParam(name = "type", required = false) ClassMappings subType) { - - Class type = endpointToClass(endpoint, subType); - return catalog.getAll(type); - } - - @GetMapping(path = {"/{endpoint}/{id}"}) - public Mono findById( // - @PathVariable("endpoint") String endpoint, - @PathVariable("id") String id, - @RequestParam(name = "type", required = false) ClassMappings subType) { - - final @NonNull ClassMappings type = endpointToType(endpoint, subType); - @SuppressWarnings("unchecked") - Class targetType = - (Class) type.getInterface(); - return catalog.getById(id, targetType) - .switchIfEmpty( - noContent( - "%s with id '%s' does not exist", - type.getInterface().getSimpleName(), id)); - } - - @GetMapping(path = "/{endpoint}/name/{name}/first") - public Mono findFirstByName( // - @PathVariable("endpoint") String endpoint, - @PathVariable(name = "name") String name, - @RequestParam(name = "type", required = false) ClassMappings subType) { - - Class type = endpointToClass(endpoint, subType); - return catalog.getFirstByName(name, type) - .switchIfEmpty( - noContent("%s with name '%s' does not exist", type.getSimpleName(), name)); - } - - @GetMapping(path = "/{endpoint}/query/cansortby/{propertyName}") - public Mono canSortBy( - @PathVariable("endpoint") String endpoint, - @PathVariable("propertyName") String propertyName) { - - Class type = endpointToClass(endpoint); - return catalog.canSortBy(type, propertyName); - } - - @GetMapping(path = "/query/capabilities/functions", produces = APPLICATION_STREAM_JSON_VALUE) - public Flux getSupportedFilterFunctionNames() { - return catalog.getSupportedFunctionNames(); - } - - @PostMapping(path = "/{endpoint}/query", produces = APPLICATION_STREAM_JSON_VALUE) - public Flux query( // - @PathVariable("endpoint") String endpoint, @RequestBody Query query) { - - return catalog.query(query); - } - - @PostMapping(path = "/{endpoint}/query/count") - public Mono count( - @PathVariable("endpoint") String endpoint, @RequestBody Query query) { - return catalog.count(query.getType(), query.getFilter()); - } - - @PutMapping(path = "/workspaces/default/{workspaceId}") - public Mono setDefaultWorkspace( - @PathVariable("workspaceId") String workspaceId) { - - return catalog.getById(workspaceId, WorkspaceInfo.class) - .switchIfEmpty(noContent("WorkspaceInfo with id '%s' does not exist", workspaceId)) - .flatMap(catalog::setDefaultWorkspace); - } - - @DeleteMapping(path = "workspaces/default") - public Mono unsetDefaultWorkspace() { - return catalog.unsetDefaultWorkspace(); - } - - @GetMapping(path = "/workspaces/default") - public Mono getDefaultWorkspace() { - return catalog.getDefaultWorkspace().switchIfEmpty(noContent("No default workspace")); - } - - @PutMapping(path = "namespaces/default/{namespaceId}") - public Mono setDefaultNamespace( - @PathVariable("namespaceId") String namespaceId) { - - return catalog.getById(namespaceId, NamespaceInfo.class) - .switchIfEmpty(noContent("Namespace %s does not exist", namespaceId)) - .flatMap(catalog::setDefaultNamespace); - } - - @DeleteMapping(path = "namespaces/default") - public Mono unsetDefaultNamespace() { - return catalog.unsetDefaultNamespace(); - } - - @GetMapping(path = "namespaces/default") - public Mono getDefaultNamespace() { - return catalog.getDefaultNamespace().switchIfEmpty(noContent("No default namespace")); - } - - @GetMapping(path = "namespaces/uri") - public Mono findOneNamespaceByURI(@RequestParam("uri") String uri) { - return catalog.getOneNamespaceByURI(uri) - .switchIfEmpty(noContent("No NamespaceInfo found for uri %s", uri)); - } - - @GetMapping(path = "namespaces/uri/all", produces = APPLICATION_STREAM_JSON_VALUE) - public Flux findAllNamespacesByURI(@RequestParam("uri") String uri) { - return catalog.getAllNamespacesByURI(uri); - } - - @GetMapping(path = "/stores/defaults", produces = APPLICATION_STREAM_JSON_VALUE) - public Flux getDefaultDataStores() { - return catalog.getDefaultDataStores(); - } - - @PutMapping(path = "/workspaces/{workspaceId}/stores/default/{dataStoreId}") - public Mono setDefaultDataStoreByWorkspaceId( // - @PathVariable("workspaceId") String workspaceId, - @PathVariable("dataStoreId") String dataStoreId) { - - Mono ws = - catalog.getById(workspaceId, WorkspaceInfo.class) - .switchIfEmpty(noContent("workspace not found")); - Mono ds = - catalog.getById(dataStoreId, DataStoreInfo.class) - .switchIfEmpty(noContent("data store not found")); - - return ws.zipWith(ds) - .flatMap(tuple -> catalog.setDefaultDataStore(tuple.getT1(), tuple.getT2())); - } - - @DeleteMapping(path = "/workspaces/{workspaceId}/stores/default") - public Mono unsetDefaultDataStore( - @PathVariable("workspaceId") String workspaceId) { - - return catalog.getById(workspaceId, WorkspaceInfo.class) - .flatMap(w -> catalog.unsetDefaultDataStore(w)) - .switchIfEmpty(noContent("Workspace does not exist: %s", workspaceId)); - } - - @GetMapping(path = "/workspaces/{workspaceId}/stores/default") - public Mono findDefaultDataStoreByWorkspaceId( // - @PathVariable("workspaceId") String workspaceId) { - - return catalog.getById(workspaceId, WorkspaceInfo.class) - .flatMap(catalog::getDefaultDataStore) - .switchIfEmpty(noContent("Workspace not found: %s", workspaceId)); - } - - @GetMapping(path = "/workspaces/{workspaceId}/stores", produces = APPLICATION_STREAM_JSON_VALUE) - public Flux findStoresByWorkspaceId( // - @PathVariable("workspaceId") String workspaceId, - @RequestParam(name = "type", required = false) ClassMappings subType) { - - @SuppressWarnings("unchecked") - final Class type = - (Class) (subType == null ? STORE : subType).getInterface(); - - return catalog.getById(workspaceId, WorkspaceInfo.class) - .flatMapMany(w -> catalog.getStoresByWorkspace(w, type)); - } - - @GetMapping(path = "/workspaces/{workspaceId}/stores/name/{name}") - public Mono findStoreByWorkspaceIdAndName( // - @PathVariable("workspaceId") String workspaceId, - @PathVariable("name") String name, - @RequestParam(name = "type", required = false) ClassMappings subType) { - - @SuppressWarnings("unchecked") - final Class type = - (Class) (subType == null ? STORE : subType).getInterface(); - return catalog.getById(workspaceId, WorkspaceInfo.class) - .flatMap(w -> catalog.getStoreByName(w, name, type)) - .switchIfEmpty(noContent("Workspace does not exist: %s", workspaceId)); - } - - @GetMapping(path = "/namespaces/{namespaceId}/resources/name/{name}") - public Mono findResourceByNamespaceIdAndName( - @PathVariable("namespaceId") String namespaceId, - @PathVariable("name") String name, - @RequestParam(name = "type", required = false) ClassMappings subType) { - - @SuppressWarnings("unchecked") - final Class type = - (Class) - (subType == null ? RESOURCE : subType).getInterface(); - - return catalog.getById(namespaceId, NamespaceInfo.class) - .flatMap(n -> catalog.getResourceByName(n, name, type)) - .switchIfEmpty(noContent("Namesapce does not exist: %s", namespaceId)); - } - - @GetMapping(path = "/layers/style/{styleId}", produces = APPLICATION_STREAM_JSON_VALUE) - public Flux findLayersWithStyle(@PathVariable("styleId") String styleId) { - return catalog.getById(styleId, StyleInfo.class) - .switchIfEmpty(noContent("Style does not exist: %s", styleId)) - .flatMapMany(s -> catalog.getLayersWithStyle(s)); - } - - @GetMapping(path = "/layers/resource/{resourceId}", produces = APPLICATION_STREAM_JSON_VALUE) - public Flux findLayersByResourceId(@PathVariable("resourceId") String resourceId) { - - return catalog.getById(resourceId, ResourceInfo.class) - .switchIfEmpty(noContent("ResourceInfo does not exist: %s", resourceId)) - .flatMapMany(r -> catalog.getLayersByResource(r)); - } - - @GetMapping(path = "/layergroups/noworkspace", produces = APPLICATION_STREAM_JSON_VALUE) - public Flux findLayerGroupsByNullWoskspace() { - return catalog.getLayerGroupsWithNoWoskspace(); - } - - @GetMapping( - path = "/workspaces/{workspaceId}/layergroups", - produces = APPLICATION_STREAM_JSON_VALUE) - public Flux findLayerGroupsByWoskspaceId( - @PathVariable("workspaceId") String workspaceId) { - - return catalog.getById(workspaceId, WorkspaceInfo.class) - .switchIfEmpty(noContent("Workspace does not exist: %s", workspaceId)) - .flatMapMany(catalog::getLayerGroupsByWoskspace); - } - - @GetMapping(path = "/layergroups/noworkspace/{name}") - public Mono findLayerGroupByNameAndNullWorkspace( - @PathVariable("name") String name) { - - // gotta use NO_WORKSPACE to bypass all the magic in catalog, better to have well defined - // contracts - return catalog.getLayerGroupByName(CatalogFacade.NO_WORKSPACE, name) - .switchIfEmpty(noContent("LayerGroup named '%s' does not exist", name)); - } - - @GetMapping(path = "/workspaces/{workspaceId}/layergroups/{name}") - public Mono findLayerGroupByWorkspaceIdAndName( - @PathVariable(required = false, name = "workspaceId") String workspaceId, - @PathVariable("name") String name) { - - return catalog.getById(workspaceId, WorkspaceInfo.class) - .flatMap(w -> catalog.getLayerGroupByName(w, name)) - .switchIfEmpty(noContent("Workspace does not exist: %s", workspaceId)); - } - - @GetMapping(path = "/styles/noworkspace", produces = APPLICATION_STREAM_JSON_VALUE) - public Flux findStylesByNullWorkspace() { - return catalog.getStylesWithNoWorkspace(); - } - - @GetMapping(path = "/workspaces/{workspaceId}/styles", produces = APPLICATION_STREAM_JSON_VALUE) - public Flux findStylesByWorkspaceId( - @PathVariable(name = "workspaceId") String workspaceId) { - - return catalog.getById(workspaceId, WorkspaceInfo.class) - .switchIfEmpty(noContent("Workspace does not exist: %s", workspaceId)) - .flatMapMany(catalog::getStylesByWorkspace); - } - - @GetMapping(path = "/workspaces/{workspaceId}/styles/{name}") - public Mono findStyleByWorkspaceIdAndName( - @PathVariable(name = "workspaceId") String workspaceId, - @PathVariable("name") String name) { - - return catalog.getById(workspaceId, WorkspaceInfo.class) - .flatMap(w -> catalog.getStyleByName(w, name)) - .switchIfEmpty(noContent("Workspace does not exist: %s", workspaceId)); - } - - @GetMapping(path = "/styles/noworkspace/{name}") - public Mono findStyleByNameAndNullWorkspace(@PathVariable("name") String name) { - - return catalog.getStyleByName(name) - .switchIfEmpty(noContent("Style named '%s' does not exist", name)); - } - - @SuppressWarnings("unchecked") - private @NonNull Class endpointToClass(@NonNull String endpoint) { - return (@NonNull Class) endpointToType(endpoint).getInterface(); - } - - private @NonNull ClassMappings endpointToType(@NonNull String endpoint) { - // e.g. "workspaces" -> "WORKSPACE" - String enumKey = endpoint.toUpperCase().substring(0, endpoint.length() - 1); - ClassMappings type = ClassMappings.valueOf(enumKey); - if (type == null) { - throw new IllegalArgumentException("Invalid end point: " + endpoint); - } - return type; - } - - @SuppressWarnings("unchecked") - private @NonNull Class endpointToClass( - @NonNull String endpoint, ClassMappings subType) { - return (@NonNull Class) - endpointToType(endpoint, subType).getInterface(); - } - - private @NonNull ClassMappings endpointToType(@NonNull String endpoint, ClassMappings subType) { - ClassMappings type = endpointToType(endpoint); - if (subType != null) { - if (!type.getInterface().isAssignableFrom(subType.getInterface())) { - throw new IllegalArgumentException( - String.format("%s is not a subtype of %s", subType, type)); - } - return subType; - } - return type; - } - - protected Mono error(HttpStatus status, String messageFormat, Object... messageArgs) { - return Mono.error( - () -> - new ResponseStatusException( - status, String.format(messageFormat, messageArgs))); - } - - /** - * We use response code 204 (No Content) to mean something was not found, to differentiate from - * the actual meaning of 404 - Not found, that the url itself is not found. - */ - protected Mono noContent(String messageFormat, Object... messageArgs) { - // revisit whether and now to return a reason message as header for debugging purposes - // ex.getResponseHeaders().add("x-debug-reason", reason); - return Mono.defer( - () -> Mono.error(() -> new ResponseStatusException(HttpStatus.NO_CONTENT))); - } -} diff --git a/src/catalog/catalog-server/server/src/main/java/org/geoserver/cloud/catalog/server/api/v1/ReactiveConfigController.java b/src/catalog/catalog-server/server/src/main/java/org/geoserver/cloud/catalog/server/api/v1/ReactiveConfigController.java deleted file mode 100644 index 14bc0676a..000000000 --- a/src/catalog/catalog-server/server/src/main/java/org/geoserver/cloud/catalog/server/api/v1/ReactiveConfigController.java +++ /dev/null @@ -1,266 +0,0 @@ -/* - * (c) 2020 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.cloud.catalog.server.api.v1; - -import static org.springframework.http.MediaType.APPLICATION_STREAM_JSON_VALUE; - -import lombok.extern.slf4j.Slf4j; - -import org.geoserver.catalog.WorkspaceInfo; -import org.geoserver.catalog.plugin.Patch; -import org.geoserver.cloud.catalog.server.service.ReactiveCatalog; -import org.geoserver.cloud.catalog.server.service.ReactiveGeoServer; -import org.geoserver.config.GeoServerInfo; -import org.geoserver.config.LoggingInfo; -import org.geoserver.config.ServiceInfo; -import org.geoserver.config.SettingsInfo; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.http.HttpStatus; -import org.springframework.web.bind.annotation.DeleteMapping; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PatchMapping; -import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.PutMapping; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.ResponseStatus; -import org.springframework.web.bind.annotation.RestController; -import org.springframework.web.server.ResponseStatusException; - -import reactor.core.publisher.Flux; -import reactor.core.publisher.Mono; - -@Slf4j -@RestController -@RequestMapping(path = ReactiveConfigController.BASE_URI) -public class ReactiveConfigController { - - public static final String BASE_URI = "/api/v1/config"; - - private @Autowired ReactiveCatalog catalog; - private @Autowired ReactiveGeoServer config; - - /** The global geoserver configuration. */ - @GetMapping("/global") - public Mono getGlobal() { - return config.getGlobal().switchIfEmpty(noContent()); - } - - /** Sets the global configuration. */ - @PutMapping("/global") - public Mono setGlobal(@RequestBody GeoServerInfo global) { - return config.setGlobal(global); - } - - /** The settings configuration by its id, or null if not exists. */ - @GetMapping("/workspaces/settings/{id}") - public Mono getSettingsById(@PathVariable("id") String id) { - return config.getSettingsById(id); - } - - /** - * The settings configuration for the specified workspace, or null if non exists. - */ - @GetMapping("/workspaces/{workspaceId}/settings") - public Mono getSettingsByWorkspace( - @PathVariable("workspaceId") String workspaceId) { - - return catalog.getById(workspaceId, WorkspaceInfo.class) - .switchIfEmpty( - badRequest("getSettingsByWorkspace: workspace %s not found", workspaceId)) - .flatMap(config::getSettingsByWorkspace) - .switchIfEmpty(noContent()); - } - - /** Adds a settings configuration for the specified workspace. */ - @PostMapping("/workspaces/{workspaceId}/settings") - @ResponseStatus(HttpStatus.CREATED) - public Mono createSettings( - @PathVariable("workspaceId") String workspaceId, @RequestBody SettingsInfo settings) { - - return catalog.getById(workspaceId, WorkspaceInfo.class) - .switchIfEmpty(badRequest("createSettings: workspace %s not found", workspaceId)) - .flatMap( - ws -> { - settings.setWorkspace(ws); - return config.add(settings); - }); - } - - /** Saves the settings configuration for the specified workspace. */ - @PatchMapping("/workspaces/{workspaceId}/settings") - Mono updateSettings( - @PathVariable("workspaceId") String workspaceId, @RequestBody Patch patch) { - - return catalog.getById(workspaceId, WorkspaceInfo.class) - .switchIfEmpty(badRequest("updateSettings: workspace %s not found", workspaceId)) - .flatMap(config::getSettingsByWorkspace) - .switchIfEmpty(badRequest("Workspace has no settings")) - .flatMap(settings -> config.update(settings, patch)); - } - - /** Removes the settings configuration for the specified workspace. */ - @DeleteMapping("/workspaces/{workspaceId}/settings") - public Mono deleteSettings(@PathVariable("workspaceId") String workspaceId) { - - return catalog.getById(workspaceId, WorkspaceInfo.class) - .switchIfEmpty(badRequest("deleteSettings: workspace %s not found", workspaceId)) - .flatMap(config::getSettings) - .switchIfEmpty(noContent()) - .flatMap(config::remove); - } - - /** The logging configuration. */ - @GetMapping("/logging") - public Mono getLogging() { - return config.getLogging().switchIfEmpty(noContent()); - } - - /** Sets logging configuration. */ - @PutMapping("/logging") - public Mono setLogging(@RequestBody LoggingInfo logging) { - return config.setLogging(logging); - } - - /** Adds a service to the configuration. */ - @PostMapping("/services") - @ResponseStatus(HttpStatus.CREATED) - public Mono createService(@RequestBody ServiceInfo service) { - if (service.getWorkspace() != null) - throw new IllegalArgumentException( - "Service has workspace, use /workspaces/{workspaceId}/services instead"); - - return config.add(service); - } - - @PostMapping("/workspaces/{workspaceId}/services") - @ResponseStatus(HttpStatus.CREATED) - public Mono createService( - @PathVariable("workspaceId") String workspaceId, @RequestBody ServiceInfo service) { - - return catalog.getById(workspaceId, WorkspaceInfo.class) - .switchIfEmpty(badRequest("createService: workspace %s not found", workspaceId)) - .flatMap( - ws -> { - service.setWorkspace(ws); - return config.add(service); - }); - } - - /** Removes a service from the configuration. */ - @DeleteMapping("/services/{serviceId}") - public Mono deleteService(@PathVariable("serviceId") String serviceId) { - return config.getServiceById(serviceId).switchIfEmpty(noContent()).flatMap(config::remove); - } - - /** Looks up a global service by id. */ - @GetMapping("/services/{serviceId}") - public Mono getServiceById(@PathVariable("serviceId") String id) { - return config.getServiceById(id); - } - - /** Saves a service that has been modified. */ - @PatchMapping("/services/{serviceId}") - Mono updateService( - @PathVariable("serviceId") String serviceId, @RequestBody Patch patch) { - - return config.getServiceById(serviceId) - .switchIfEmpty(badRequest("Service %s not found", serviceId)) - .flatMap(s -> config.update(s, patch)); - } - - /** GeoServer services specific to the specified workspace. */ - @GetMapping( - path = "/workspaces/{workspaceId}/services", - produces = APPLICATION_STREAM_JSON_VALUE) - public Flux getServicesByWorkspace( - @PathVariable("workspaceId") String workspaceId) { - - return catalog.getById(workspaceId, WorkspaceInfo.class) - .switchIfEmpty( - badRequest("getServicesByWorkspace: Workspace %s not found", workspaceId)) - .flatMapMany(config::getServicesByWorkspace); - } - - /** Global (no-workspace) services. */ - @GetMapping(path = "/services", produces = APPLICATION_STREAM_JSON_VALUE) - public Flux getGlobalServices() { - return config.getGlobalServices(); - } - - /** GeoServer global service filtered by class. */ - @GetMapping("/services/type/{type}") - public Mono getGlobalServiceByType(@PathVariable("type") String clazz) { - - Class type = asSericeType(clazz); - return config.getGlobalService(type).switchIfEmpty(noContent()); - } - - @SuppressWarnings("unchecked") - private Class asSericeType(String clazz) { - try { - Class type = Class.forName(clazz); - if (!ServiceInfo.class.isAssignableFrom(type)) - throw new IllegalArgumentException("Not a subclass of ServiceInfo: " + clazz); - if (!type.isInterface()) - throw new IllegalArgumentException("Not an interface: " + clazz); - return (Class) type; - } catch (ClassNotFoundException e) { - throw new IllegalArgumentException("Class not found: " + clazz); - } - } - - /** GeoServer service specific to the specified workspace and filtered by class. */ - @GetMapping("/workspaces/{workspaceId}/services/type/{type}") - public Mono getServiceByWorkspaceAndType( - @PathVariable("workspaceId") String workspaceId, @PathVariable("type") String clazz) { - - final Class type = this.asSericeType(clazz); - - return catalog.getById(workspaceId, WorkspaceInfo.class) - .switchIfEmpty( - badRequest( - "getServiceByWorkspaceAndType: Workspace %s not found", - workspaceId)) - .flatMap(w -> config.getServiceByWorkspaceAndType(w, type)) - .switchIfEmpty(noContent()); - } - - /** Looks up a service by name. */ - @GetMapping("/services/name/{name}") - public Mono getGlobalServiceByName(@PathVariable("name") String name) { - - return config.getGlobalServiceByName(name).switchIfEmpty(noContent()); - } - - /** Looks up a service by name, specific to the specified workspace. */ - @GetMapping("/workspaces/{workspaceId}/services/name/{name}") - public Mono getServiceByWorkspaceAndName( - @PathVariable("workspaceId") String workspaceId, @PathVariable("name") String name) { - - return catalog.getById(workspaceId, WorkspaceInfo.class) - .switchIfEmpty( - badRequest( - "getServiceByWorkspaceAndName: Workspace %s not found", - workspaceId)) - .flatMap(ws -> config.getServiceByWorkspaceAndName(ws, name)) - .switchIfEmpty(noContent()); - } - - protected Mono noContent() { - return Mono.defer( - () -> Mono.error(() -> new ResponseStatusException(HttpStatus.NO_CONTENT))); - } - - protected Mono badRequest(String messageFormat, Object... messageArgs) { - return Mono.error( - () -> { - String msg = String.format(messageFormat, messageArgs); - log.warn(msg); - return new ResponseStatusException(HttpStatus.BAD_REQUEST, msg); - }); - } -} diff --git a/src/catalog/catalog-server/server/src/main/java/org/geoserver/cloud/catalog/server/api/v1/ReactiveResourceStoreController.java b/src/catalog/catalog-server/server/src/main/java/org/geoserver/cloud/catalog/server/api/v1/ReactiveResourceStoreController.java deleted file mode 100644 index 93ec53af4..000000000 --- a/src/catalog/catalog-server/server/src/main/java/org/geoserver/cloud/catalog/server/api/v1/ReactiveResourceStoreController.java +++ /dev/null @@ -1,183 +0,0 @@ -/* - * (c) 2020 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.cloud.catalog.server.api.v1; - -import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE; -import static org.springframework.http.MediaType.APPLICATION_OCTET_STREAM_VALUE; -import static org.springframework.http.MediaType.APPLICATION_STREAM_JSON_VALUE; - -import com.fasterxml.jackson.annotation.JsonIgnore; -import com.fasterxml.jackson.annotation.JsonProperty; - -import lombok.Data; -import lombok.NoArgsConstructor; -import lombok.NonNull; - -import org.geoserver.cloud.catalog.server.service.ReactiveResourceStore; -import org.geoserver.platform.resource.Resource; -import org.geoserver.platform.resource.Resource.Type; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.core.io.FileSystemResource; -import org.springframework.core.io.InputStreamResource; -import org.springframework.http.HttpStatus; -import org.springframework.web.bind.annotation.DeleteMapping; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.PutMapping; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; -import org.springframework.web.server.ResponseStatusException; - -import reactor.core.publisher.Flux; -import reactor.core.publisher.Mono; - -import java.nio.ByteBuffer; -import java.util.Objects; - -/** */ -@RestController -@RequestMapping(path = ReactiveResourceStoreController.BASE_URI) -public class ReactiveResourceStoreController { - - public static final String BASE_URI = "/api/v1/resources"; - - private @Autowired ReactiveResourceStore store; - - @Data - @NoArgsConstructor - public static class WebResource { - - private @JsonIgnore Resource resource; - private @JsonIgnore String incomingPath; - private @JsonIgnore Resource.Type incomingType; - private @JsonIgnore long incomingLastModified; - - public WebResource(@NonNull Resource resource) { - this.resource = resource; - } - - public @JsonProperty @NonNull String getPath() { - return resource == null ? incomingPath : resource.path(); - } - - public @JsonProperty @NonNull Resource.Type getType() { - return resource == null ? incomingType : resource.getType(); - } - - public @JsonProperty long getLastModified() { - return resource == null ? incomingLastModified : resource.lastmodified(); - } - - public void setPath(@NonNull String path) { - this.incomingPath = path; - } - - public void setLastModified(long lastModified) { - this.incomingLastModified = lastModified; - } - - public void setType(@NonNull Type type) { - this.incomingType = type; - } - } - - private WebResource toWebResource(Resource r) { - return new WebResource(r); - } - - @GetMapping( - path = "/{*path}", - produces = {APPLICATION_STREAM_JSON_VALUE}) - public Flux list(@PathVariable("path") String path) { - return store.get(path).flatMapMany(store::list).map(this::toWebResource); - } - - @GetMapping(path = "/{*path}", produces = APPLICATION_JSON_VALUE) - public Mono describe(@PathVariable("path") String path) { - return store.get(path).map(this::toWebResource); - } - - @PutMapping( - path = "/{*path}", - consumes = APPLICATION_OCTET_STREAM_VALUE, - produces = APPLICATION_JSON_VALUE) - public Mono put( - @PathVariable("path") String path, @RequestBody ByteBuffer contents) { - - return this.store.setContents(path, contents).map(this::toWebResource); - } - - @GetMapping( - path = "/{*path}", - produces = {APPLICATION_OCTET_STREAM_VALUE}) - public Mono getFileContent( - @PathVariable("path") String path) { - return store.get(path).map(this::toSpringResource); - } - - // can't use instanceof, FileSystemResourceStore.FileSystemResource is package private - private Class zeroCopyResourceType; - - private org.springframework.core.io.Resource toSpringResource(Resource gsResource) { - final Type type = gsResource.getType(); - if (type == Type.DIRECTORY) - throw new ResponseStatusException( - HttpStatus.BAD_REQUEST, gsResource.path() + " is a directory, not a file"); - if (type == Type.UNDEFINED) - throw new ResponseStatusException( - HttpStatus.NOT_FOUND, gsResource.path() + " does not exist"); - - // can't use instanceof, FileSystemResourceStore.FileSystemResource is package private - Class resourceType = gsResource.getClass(); - if (zeroCopyResourceType != null && resourceType == zeroCopyResourceType) { - // leverage zero-copy transfer - return new FileSystemResource(gsResource.file()); - } - final String resourceClassName = resourceType.getCanonicalName(); - if ("org.geoserver.platform.resource.FileSystemResourceStore.FileSystemResource" - .equals(resourceClassName)) { - zeroCopyResourceType = resourceType; - // leverage zero-copy transfer - return new FileSystemResource(gsResource.file()); - } - return new InputStreamResource(gsResource.in()); - } - - @PostMapping("/{*path}") - public Mono create( - @PathVariable("path") String path, @RequestBody WebResource resource) { - - return store.create(path, resource.getType()).map(this::toWebResource); - } - - @PutMapping("/{*path}") - public Mono update( - @PathVariable("path") String path, @RequestBody WebResource resource) { - - Objects.requireNonNull(resource.getPath()); - - Mono updated = - store.get(path) - .filter(r -> r.getType() != Type.UNDEFINED) - .switchIfEmpty( - Mono.error( - () -> new ResponseStatusException(HttpStatus.NO_CONTENT))) - .flatMap( - r -> { - if (!Objects.equals(r.path(), resource.getPath())) { - return store.move(r.path(), resource.getPath()); - } - return Mono.just(r); - }); - return updated.map(this::toWebResource); - } - - @DeleteMapping("/{*path}") - public Mono delete(@PathVariable("path") String path) { - return store.remove(path); - } -} diff --git a/src/catalog/catalog-server/server/src/main/java/org/geoserver/cloud/catalog/server/config/CatalogServerConfigProperties.java b/src/catalog/catalog-server/server/src/main/java/org/geoserver/cloud/catalog/server/config/CatalogServerConfigProperties.java deleted file mode 100644 index cb37d37ce..000000000 --- a/src/catalog/catalog-server/server/src/main/java/org/geoserver/cloud/catalog/server/config/CatalogServerConfigProperties.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * (c) 2020 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.cloud.catalog.server.config; - -import lombok.Data; - -/** - * {@code catalog-service} specific configuration properties bean, expected to match the {@code - * geoserver.catalog-service} properties prefix - */ -public @Data class CatalogServerConfigProperties { - - private SchedulerConfig ioThreads = new SchedulerConfig(); - - public static @Data class SchedulerConfig { - public static final int DEFAULT_MAX_SIZE = - Math.max(4, 4 * Runtime.getRuntime().availableProcessors()); - public static final int DEFAULT_MAX_QUEUED = Integer.MAX_VALUE; - - Integer maxSize = DEFAULT_MAX_SIZE; - Integer maxQueued = DEFAULT_MAX_QUEUED; - - public Integer getMaxSize() { - return maxSize == null ? DEFAULT_MAX_SIZE : maxSize; - } - - public Integer getMaxQueued() { - return maxQueued == null ? DEFAULT_MAX_QUEUED : maxQueued; - } - - public static String buildInvalidMaxSizeMessage(int providedMaxThreadsValue) { - return String.format( - "Ivalid value for geoserver.catalog-service.io-threads.max-size=%d, using default value of 4*cores (%d)", - providedMaxThreadsValue, SchedulerConfig.DEFAULT_MAX_SIZE); - } - - public static String buildInvalidMaxQueuedMessage(int maxQueued) { - return String.format( - "Ivalid value for geoserver.catalog-service.io-threads.max-queued=%d, using default unbounded queue", - maxQueued); - } - } -} diff --git a/src/catalog/catalog-server/server/src/main/java/org/geoserver/cloud/catalog/server/config/CatalogServerConfiguration.java b/src/catalog/catalog-server/server/src/main/java/org/geoserver/cloud/catalog/server/config/CatalogServerConfiguration.java deleted file mode 100644 index 1b5e390d8..000000000 --- a/src/catalog/catalog-server/server/src/main/java/org/geoserver/cloud/catalog/server/config/CatalogServerConfiguration.java +++ /dev/null @@ -1,79 +0,0 @@ -/* - * (c) 2020 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.cloud.catalog.server.config; - -import lombok.extern.slf4j.Slf4j; - -import org.geoserver.cloud.catalog.server.api.v1.ReactiveCatalogController; -import org.geoserver.cloud.catalog.server.config.CatalogServerConfigProperties.SchedulerConfig; -import org.geoserver.cloud.catalog.server.service.ReactiveCatalog; -import org.springframework.boot.context.properties.ConfigurationProperties; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.ComponentScan; -import org.springframework.context.annotation.Configuration; -import org.springframework.web.reactive.config.WebFluxConfigurer; - -import reactor.core.scheduler.Scheduler; -import reactor.core.scheduler.Schedulers; - -@Configuration -@ComponentScan(basePackageClasses = {ReactiveCatalog.class, ReactiveCatalogController.class}) -@Slf4j -public class CatalogServerConfiguration implements WebFluxConfigurer { - - /** Global Jackson ObjectMapper, configured in {@link #configureHttpMessageCodecs} */ - // private @Autowired ObjectMapper objectMapper; - - @ConfigurationProperties(prefix = "geoserver.catalog-service") - @Bean - CatalogServerConfigProperties applicationConfig() { - return new CatalogServerConfigProperties(); - } - - /** - * Configures the reactive Scheduler thread pool on which {@link ReactiveCatalogService} - * performs the blocking catalog calls - */ - @Bean - Scheduler catalogScheduler() { - CatalogServerConfigProperties config = applicationConfig(); - SchedulerConfig schedulerConfig = config.getIoThreads(); - int maxThreads = schedulerConfig.getMaxSize(); - int maxQueued = schedulerConfig.getMaxQueued(); - if (maxThreads <= 0) { - log.warn(SchedulerConfig.buildInvalidMaxSizeMessage(maxThreads)); - maxThreads = SchedulerConfig.DEFAULT_MAX_SIZE; - } - if (maxQueued <= 0) { - log.warn(SchedulerConfig.buildInvalidMaxQueuedMessage(maxQueued)); - maxQueued = SchedulerConfig.DEFAULT_MAX_QUEUED; - } - log.info("configured catalogScheduler: maxThreads={}, maxQueued={}", maxThreads, maxQueued); - return Schedulers.newBoundedElastic(maxThreads, maxQueued, "catalogScheduler"); - } - - /** - * Configures the {@link ObjectMapper} used by {@link Jackson2JsonEncoder} and {@link - * Jackson2JsonDecoder} to handle http message payloads, especially in order to set {@link - * SerializationFeature#WRAP_ROOT_VALUE} to {@code false}, or the responses are like - * {"WorkspaceInfoImpl" : {"Workspace" : {"WorkspaceInfo" : {...}}}} - * instead of like - * {"WorkspaceInfo" : {...}} - * - */ - // @Bean ObjectMapper objectMapper() { - // ObjectMapper objectMapper = new ObjectMapper(); - // objectMapper.configure(SerializationFeature.WRAP_ROOT_VALUE, false); - // objectMapper.configure(DeserializationFeature.UNWRAP_ROOT_VALUE, false); - // - // objectMapper.setDefaultPropertyInclusion(Include.NON_EMPTY); - // - // objectMapper.configure(SerializationFeature.WRITE_SINGLE_ELEM_ARRAYS_UNWRAPPED, - // false); - // objectMapper.configure(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY, true); - // objectMapper.findAndRegisterModules(); - // return objectMapper; - // } -} diff --git a/src/catalog/catalog-server/server/src/main/java/org/geoserver/cloud/catalog/server/service/BlockingCatalog.java b/src/catalog/catalog-server/server/src/main/java/org/geoserver/cloud/catalog/server/service/BlockingCatalog.java deleted file mode 100644 index f4e300071..000000000 --- a/src/catalog/catalog-server/server/src/main/java/org/geoserver/cloud/catalog/server/service/BlockingCatalog.java +++ /dev/null @@ -1,211 +0,0 @@ -/* - * (c) 2020 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.cloud.catalog.server.service; - -import lombok.NonNull; -import lombok.extern.slf4j.Slf4j; - -import org.geoserver.catalog.Catalog; -import org.geoserver.catalog.CatalogCapabilities; -import org.geoserver.catalog.CatalogFacade; -import org.geoserver.catalog.CatalogInfo; -import org.geoserver.catalog.DataStoreInfo; -import org.geoserver.catalog.LayerGroupInfo; -import org.geoserver.catalog.LayerInfo; -import org.geoserver.catalog.MapInfo; -import org.geoserver.catalog.NamespaceInfo; -import org.geoserver.catalog.ResourceInfo; -import org.geoserver.catalog.StoreInfo; -import org.geoserver.catalog.StyleInfo; -import org.geoserver.catalog.WorkspaceInfo; -import org.geoserver.catalog.impl.AbstractCatalogDecorator; -import org.geoserver.catalog.plugin.CatalogPlugin; -import org.geoserver.catalog.plugin.Patch; -import org.geoserver.catalog.plugin.Query; -import org.geoserver.catalog.plugin.forwarding.ForwardingCatalogFacade; -import org.geoserver.catalog.util.CloseableIterator; -import org.geotools.api.filter.Filter; -import org.geotools.api.filter.sort.SortBy; -import org.springframework.beans.factory.annotation.Qualifier; -import org.springframework.stereotype.Component; - -import java.util.Spliterator; -import java.util.Spliterators; -import java.util.stream.Stream; -import java.util.stream.StreamSupport; - -/** */ -@Component -@Slf4j -@SuppressWarnings("serial") -public class BlockingCatalog extends AbstractCatalogDecorator { - - private static class AllowAllCatalogFacade extends ForwardingCatalogFacade { - /** - * {@link CatalogCapabilities#supportsIsolatedWorkspaces()} is {@code true} to allow - * bypassing the workspace validation check in {@link CatalogPlugin#validate(WorkspaceInfo, - * boolean)}, that otherwise would throw an {@link IllegalArgumentException} when creating - * or updating an isolated workspace, but this service has to work as a raw catalog. - */ - private static final CatalogCapabilities CATALOG_CAPABILITIES = new CatalogCapabilities(); - - static { - CATALOG_CAPABILITIES.setIsolatedWorkspacesSupport(true); - } - - public AllowAllCatalogFacade(CatalogFacade facade) { - super(facade); - } - - @Override - public CatalogCapabilities getCatalogCapabilities() { - return CATALOG_CAPABILITIES; - } - } - - public BlockingCatalog(@Qualifier("rawCatalog") Catalog rawCatalog) { - super(rawCatalog); - // Make sure isolated workspaces can be created/updated - if (rawCatalog instanceof org.geoserver.catalog.plugin.CatalogPlugin plugin) { - plugin.getRawFacade().getCatalogCapabilities().setIsolatedWorkspacesSupport(true); - } else if (rawCatalog instanceof org.geoserver.catalog.impl.CatalogImpl impl) { - impl.setFacade(new AllowAllCatalogFacade(impl.getFacade())); - } - } - - @SuppressWarnings("unchecked") - public C get(String id, Class type) { - if (WorkspaceInfo.class.isAssignableFrom(type)) return type.cast(delegate.getWorkspace(id)); - if (NamespaceInfo.class.isAssignableFrom(type)) return type.cast(delegate.getNamespace(id)); - if (StoreInfo.class.isAssignableFrom(type)) - return type.cast(delegate.getStore(id, (Class) type)); - if (ResourceInfo.class.isAssignableFrom(type)) - return type.cast(delegate.getResource(id, (Class) type)); - if (LayerInfo.class.isAssignableFrom(type)) return type.cast(delegate.getLayer(id)); - if (LayerGroupInfo.class.isAssignableFrom(type)) - return type.cast(delegate.getLayerGroup(id)); - if (StyleInfo.class.isAssignableFrom(type)) return type.cast(delegate.getStyle(id)); - if (MapInfo.class.isAssignableFrom(type)) return type.cast(delegate.getMap(id)); - throw new IllegalArgumentException("unknown CatalogInfo class: " + type.getCanonicalName()); - } - - public C add(@NonNull C info) { - Class type = info.getClass(); - if (WorkspaceInfo.class.isAssignableFrom(type)) delegate.add((WorkspaceInfo) info); - else if (NamespaceInfo.class.isAssignableFrom(type)) delegate.add((NamespaceInfo) info); - else if (StoreInfo.class.isAssignableFrom(type)) delegate.add((StoreInfo) info); - else if (ResourceInfo.class.isAssignableFrom(type)) delegate.add((ResourceInfo) info); - else if (LayerInfo.class.isAssignableFrom(type)) delegate.add((LayerInfo) info); - else if (LayerGroupInfo.class.isAssignableFrom(type)) delegate.add((LayerGroupInfo) info); - else if (StyleInfo.class.isAssignableFrom(type)) delegate.add((StyleInfo) info); - else if (MapInfo.class.isAssignableFrom(type)) delegate.add((MapInfo) info); - else - throw new IllegalArgumentException( - "Unknown CatalogInfo type: " + type.getCanonicalName()); - return info; - } - - public C update(@NonNull C info, @NonNull Patch patch) { - - try { - patch.applyTo(info); - } catch (RuntimeException e) { - log.error("Error applying patch to {}: {}", info, patch, e); - throw e; - } - // need to make it work with old catalogs too, jdbcconfig has not been upgraded for example - Class type = info.getClass(); - try { - if (WorkspaceInfo.class.isAssignableFrom(type)) delegate.save((WorkspaceInfo) info); - else if (NamespaceInfo.class.isAssignableFrom(type)) - delegate.save((NamespaceInfo) info); - else if (StoreInfo.class.isAssignableFrom(type)) delegate.save((StoreInfo) info); - else if (ResourceInfo.class.isAssignableFrom(type)) delegate.save((ResourceInfo) info); - else if (LayerInfo.class.isAssignableFrom(type)) delegate.save((LayerInfo) info); - else if (LayerGroupInfo.class.isAssignableFrom(type)) - delegate.save((LayerGroupInfo) info); - else if (StyleInfo.class.isAssignableFrom(type)) delegate.save((StyleInfo) info); - else if (MapInfo.class.isAssignableFrom(type)) delegate.save((MapInfo) info); - else - throw new IllegalArgumentException( - "Unknown CatalogInfo type: " + type.getCanonicalName()); - } catch (RuntimeException e) { - log.error("Error saving {} with patch {}", info, patch, e); - throw e; - } - return info; - } - - public C delete(@NonNull C info) { - Class type = info.getClass(); - if (WorkspaceInfo.class.isAssignableFrom(type)) delegate.remove((WorkspaceInfo) info); - else if (NamespaceInfo.class.isAssignableFrom(type)) delegate.remove((NamespaceInfo) info); - else if (StoreInfo.class.isAssignableFrom(type)) delegate.remove((StoreInfo) info); - else if (ResourceInfo.class.isAssignableFrom(type)) delegate.remove((ResourceInfo) info); - else if (LayerInfo.class.isAssignableFrom(type)) delegate.remove((LayerInfo) info); - else if (LayerGroupInfo.class.isAssignableFrom(type)) - delegate.remove((LayerGroupInfo) info); - else if (StyleInfo.class.isAssignableFrom(type)) delegate.remove((StyleInfo) info); - else if (MapInfo.class.isAssignableFrom(type)) delegate.remove((MapInfo) info); - return info; - } - - @SuppressWarnings("unchecked") - public C getByName( - @NonNull String name, @NonNull Class type) { - - if (WorkspaceInfo.class.isAssignableFrom(type)) - return type.cast(delegate.getWorkspaceByName(name)); - if (NamespaceInfo.class.isAssignableFrom(type)) - return type.cast(delegate.getNamespaceByPrefix(name)); - if (StoreInfo.class.isAssignableFrom(type)) - return type.cast(delegate.getStoreByName(name, (Class) type)); - if (ResourceInfo.class.isAssignableFrom(type)) - return type.cast( - delegate.getResourceByName(name, (Class) type)); - if (LayerInfo.class.isAssignableFrom(type)) return type.cast(delegate.getLayerByName(name)); - if (LayerGroupInfo.class.isAssignableFrom(type)) - return type.cast(delegate.getLayerGroupByName(name)); - if (StyleInfo.class.isAssignableFrom(type)) return type.cast(delegate.getStyleByName(name)); - if (MapInfo.class.isAssignableFrom(type)) return type.cast(delegate.getMapByName(name)); - throw new IllegalArgumentException("Unknown CatalogInfo type: " + type.getCanonicalName()); - } - - public Stream query(@NonNull Query query) { - - Class type = query.getType(); - Filter filter = query.getFilter(); - Integer offset = query.getOffset(); - Integer count = query.getCount(); - SortBy sortBy = query.getSortBy().isEmpty() ? null : query.getSortBy().get(0); - - CloseableIterator iterator; - try { - iterator = delegate.list(type, filter, offset, count, sortBy); - } catch (RuntimeException e) { - e.printStackTrace(); - throw e; - // if(!Filter.INCLUDE.equals(filter)) { - // iterator = delegate.list(type, Filter.INCLUDE, null, null, sortBy); - // } - } - int characteristics = Spliterator.DISTINCT | Spliterator.NONNULL; - Spliterator spliterator = Spliterators.spliteratorUnknownSize(iterator, characteristics); - boolean parallel = false; - Stream stream = StreamSupport.stream(spliterator, parallel); - stream.onClose(iterator::close); - - return stream; - } - - public Stream getNamespacesByURI(String uri) { - return getFacade().getNamespacesByURI(uri).stream(); - } - - public Stream getDefaultDataStores() { - Stream workspaces = query(Query.all(WorkspaceInfo.class)); - return workspaces.map(delegate::getDefaultDataStore).filter(d -> d != null); - } -} diff --git a/src/catalog/catalog-server/server/src/main/java/org/geoserver/cloud/catalog/server/service/CatalogInfoRepositoryProvider.java b/src/catalog/catalog-server/server/src/main/java/org/geoserver/cloud/catalog/server/service/CatalogInfoRepositoryProvider.java deleted file mode 100644 index 5fd4f6ef6..000000000 --- a/src/catalog/catalog-server/server/src/main/java/org/geoserver/cloud/catalog/server/service/CatalogInfoRepositoryProvider.java +++ /dev/null @@ -1,101 +0,0 @@ -/* - * (c) 2020 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.cloud.catalog.server.service; - -import static org.geoserver.catalog.impl.ClassMappings.LAYER; -import static org.geoserver.catalog.impl.ClassMappings.LAYERGROUP; -import static org.geoserver.catalog.impl.ClassMappings.MAP; -import static org.geoserver.catalog.impl.ClassMappings.NAMESPACE; -import static org.geoserver.catalog.impl.ClassMappings.RESOURCE; -import static org.geoserver.catalog.impl.ClassMappings.STORE; -import static org.geoserver.catalog.impl.ClassMappings.STYLE; -import static org.geoserver.catalog.impl.ClassMappings.WORKSPACE; - -import lombok.AllArgsConstructor; -import lombok.Getter; -import lombok.NoArgsConstructor; -import lombok.NonNull; -import lombok.Setter; -import lombok.experimental.Accessors; - -import org.geoserver.catalog.CatalogInfo; -import org.geoserver.catalog.Info; -import org.geoserver.catalog.impl.ClassMappings; -import org.geoserver.catalog.plugin.CatalogInfoRepository; -import org.geoserver.catalog.plugin.CatalogInfoRepository.LayerGroupRepository; -import org.geoserver.catalog.plugin.CatalogInfoRepository.LayerRepository; -import org.geoserver.catalog.plugin.CatalogInfoRepository.MapRepository; -import org.geoserver.catalog.plugin.CatalogInfoRepository.NamespaceRepository; -import org.geoserver.catalog.plugin.CatalogInfoRepository.ResourceRepository; -import org.geoserver.catalog.plugin.CatalogInfoRepository.StoreRepository; -import org.geoserver.catalog.plugin.CatalogInfoRepository.StyleRepository; -import org.geoserver.catalog.plugin.CatalogInfoRepository.WorkspaceRepository; - -import java.util.EnumMap; -import java.util.function.Supplier; - -// revisit, replaced by BlockingCatalog -// @Component -@NoArgsConstructor -@AllArgsConstructor -@Accessors(fluent = true) -public class CatalogInfoRepositoryProvider { - - private @Getter @Setter WorkspaceRepository workspaces; - private @Getter @Setter NamespaceRepository namespaces; - private @Getter @Setter StoreRepository stores; - private @Getter @Setter ResourceRepository resources; - private @Getter @Setter LayerRepository layers; - private @Getter @Setter LayerGroupRepository layerGroups; - private @Getter @Setter StyleRepository styles; - private @Getter @Setter MapRepository maps; - - private final EnumMap>> repos = - registerRepositories(); - - public > @NonNull R of( - @NonNull Class type) { - - @SuppressWarnings("unchecked") - R repository = (R) repos.get(toKey(type)).get(); - return repository; - } - - private @NonNull ClassMappings toKey(@NonNull Class type) { - ClassMappings mappings = ClassMappings.fromInterface(type); - if (mappings == null) mappings = ClassMappings.fromImpl(type); - return mappings; - } - - private EnumMap>> registerRepositories() { - - EnumMap>> repos; - repos = new EnumMap<>(ClassMappings.class); - - registerRepository(repos, WORKSPACE, this::workspaces); - registerRepository(repos, NAMESPACE, this::namespaces); - registerRepository(repos, STORE, this::stores); - registerRepository(repos, RESOURCE, this::resources); - registerRepository(repos, LAYER, this::layers); - registerRepository(repos, LAYERGROUP, this::layerGroups); - registerRepository(repos, STYLE, this::styles); - registerRepository(repos, MAP, this::maps); - return repos; - } - - private static void registerRepository( - EnumMap>> repos, - ClassMappings typeDef, - Supplier> supplier) { - repos.put(typeDef, supplier); - final Class baseType = typeDef.getInterface(); - Class[] concreteInterfaces = typeDef.concreteInterfaces(); - for (Class i : concreteInterfaces) { - if (!(baseType.equals(i))) { - repos.put(ClassMappings.fromInterface(i), supplier); - } - } - } -} diff --git a/src/catalog/catalog-server/server/src/main/java/org/geoserver/cloud/catalog/server/service/ProxyResolver.java b/src/catalog/catalog-server/server/src/main/java/org/geoserver/cloud/catalog/server/service/ProxyResolver.java deleted file mode 100644 index 07cbaab07..000000000 --- a/src/catalog/catalog-server/server/src/main/java/org/geoserver/cloud/catalog/server/service/ProxyResolver.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * (c) 2020 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.cloud.catalog.server.service; - -import org.geoserver.catalog.Catalog; -import org.geoserver.catalog.Info; -import org.geoserver.catalog.plugin.Patch; -import org.geoserver.catalog.plugin.resolving.ProxyUtils; -import org.geoserver.config.GeoServer; -import org.springframework.stereotype.Service; - -import reactor.core.publisher.Mono; -import reactor.core.scheduler.Schedulers; - -import java.util.Optional; - -/** */ -@Service -public class ProxyResolver { - - private ProxyUtils blockingResolver; - - public ProxyResolver(Catalog catalog, GeoServer config) { - this.blockingResolver = new ProxyUtils(catalog, Optional.of(config)); - } - - public Mono resolve(C info) { - return Mono.just(info).subscribeOn(Schedulers.parallel()).map(blockingResolver::resolve); - } - - public Mono resolve(Patch patch) { - return Mono.just(patch).subscribeOn(Schedulers.parallel()).map(blockingResolver::resolve); - } -} diff --git a/src/catalog/catalog-server/server/src/main/java/org/geoserver/cloud/catalog/server/service/ReactiveCatalog.java b/src/catalog/catalog-server/server/src/main/java/org/geoserver/cloud/catalog/server/service/ReactiveCatalog.java deleted file mode 100644 index 8f2a4dbbc..000000000 --- a/src/catalog/catalog-server/server/src/main/java/org/geoserver/cloud/catalog/server/service/ReactiveCatalog.java +++ /dev/null @@ -1,102 +0,0 @@ -/* - * (c) 2020 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.cloud.catalog.server.service; - -import lombok.NonNull; - -import org.geoserver.catalog.CatalogInfo; -import org.geoserver.catalog.DataStoreInfo; -import org.geoserver.catalog.LayerGroupInfo; -import org.geoserver.catalog.LayerInfo; -import org.geoserver.catalog.NamespaceInfo; -import org.geoserver.catalog.ResourceInfo; -import org.geoserver.catalog.StoreInfo; -import org.geoserver.catalog.StyleInfo; -import org.geoserver.catalog.WorkspaceInfo; -import org.geoserver.catalog.plugin.Patch; -import org.geoserver.catalog.plugin.Query; -import org.geotools.api.filter.Filter; -import org.geotools.api.filter.capability.FunctionName; - -import reactor.core.publisher.Flux; -import reactor.core.publisher.Mono; - -public interface ReactiveCatalog { - - Mono create(@NonNull Mono info); - - Mono update(@NonNull C info, @NonNull Mono patch); - - Mono delete(@NonNull C value); - - Flux getAll(@NonNull Class type); - - Mono getById(@NonNull String id, @NonNull Class type); - - Mono getFirstByName(@NonNull String name, @NonNull Class type); - - Mono canSortBy(Class type, String propertyName); - - Flux query(@NonNull Query query); - - Mono count(@NonNull Class type, @NonNull Filter filter); - - Mono setDefaultWorkspace(@NonNull WorkspaceInfo workspace); - - Mono unsetDefaultWorkspace(); - - Mono getDefaultWorkspace(); - - Mono setDefaultNamespace(@NonNull NamespaceInfo namespace); - - Mono unsetDefaultNamespace(); - - Mono getDefaultNamespace(); - - Mono getOneNamespaceByURI(@NonNull String uri); - - Flux getAllNamespacesByURI(@NonNull String uri); - - Flux getDefaultDataStores(); - - Mono setDefaultDataStore( - @NonNull WorkspaceInfo workspace, @NonNull DataStoreInfo dataStore); - - Mono unsetDefaultDataStore(@NonNull WorkspaceInfo workspace); - - Mono getDefaultDataStore(@NonNull WorkspaceInfo workspace); - - Flux getStoresByWorkspace( - @NonNull WorkspaceInfo workspace, @NonNull Class type); - - Mono getStoreByName( - @NonNull WorkspaceInfo workspace, @NonNull String name, Class type); - - Mono getResourceByName( - @NonNull NamespaceInfo namespace, @NonNull String name, @NonNull Class type); - - Flux getLayersWithStyle(@NonNull StyleInfo style); - - Flux getLayersByResource(@NonNull ResourceInfo resource); - - Flux getLayerGroupsWithNoWoskspace(); - - Flux getLayerGroupsByWoskspace(@NonNull WorkspaceInfo workspace); - - Mono getLayerGroupByName(@NonNull String name); - - Mono getLayerGroupByName( - @NonNull WorkspaceInfo workspace, @NonNull String name); - - Flux getStylesWithNoWorkspace(); - - Flux getStylesByWorkspace(@NonNull WorkspaceInfo workspace); - - Mono getStyleByName(@NonNull WorkspaceInfo workspace, @NonNull String name); - - Mono getStyleByName(@NonNull String name); - - Flux getSupportedFunctionNames(); -} diff --git a/src/catalog/catalog-server/server/src/main/java/org/geoserver/cloud/catalog/server/service/ReactiveCatalogImpl.java b/src/catalog/catalog-server/server/src/main/java/org/geoserver/cloud/catalog/server/service/ReactiveCatalogImpl.java deleted file mode 100644 index bfa03f49b..000000000 --- a/src/catalog/catalog-server/server/src/main/java/org/geoserver/cloud/catalog/server/service/ReactiveCatalogImpl.java +++ /dev/null @@ -1,342 +0,0 @@ -/* - * (c) 2020 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.cloud.catalog.server.service; - -import lombok.NonNull; -import lombok.extern.slf4j.Slf4j; - -import org.geoserver.catalog.CatalogFacade; -import org.geoserver.catalog.CatalogInfo; -import org.geoserver.catalog.DataStoreInfo; -import org.geoserver.catalog.LayerGroupInfo; -import org.geoserver.catalog.LayerInfo; -import org.geoserver.catalog.NamespaceInfo; -import org.geoserver.catalog.ResourceInfo; -import org.geoserver.catalog.StoreInfo; -import org.geoserver.catalog.StyleInfo; -import org.geoserver.catalog.WorkspaceInfo; -import org.geoserver.catalog.plugin.Patch; -import org.geoserver.catalog.plugin.Query; -import org.geoserver.function.IsInstanceOf; -import org.geotools.api.filter.Filter; -import org.geotools.api.filter.capability.FunctionName; -import org.geotools.api.parameter.Parameter; -import org.geotools.api.referencing.crs.CoordinateReferenceSystem; -import org.geotools.filter.FunctionFinder; -import org.geotools.geometry.jts.ReferencedEnvelope; -import org.locationtech.jts.geom.Geometry; -import org.springframework.beans.factory.annotation.Qualifier; -import org.springframework.stereotype.Service; - -import reactor.core.publisher.Flux; -import reactor.core.publisher.Mono; -import reactor.core.scheduler.Scheduler; - -import java.util.Arrays; -import java.util.Date; -import java.util.LinkedList; -import java.util.List; -import java.util.concurrent.Callable; -import java.util.stream.Collectors; -import java.util.stream.Stream; - -/** */ -@Service -@Slf4j -public class ReactiveCatalogImpl implements ReactiveCatalog { - - private Scheduler catalogScheduler; - - private BlockingCatalog blockingCatalog; - - /** - * @see #getSupportedFunctionNames() - */ - private List supportedFilterFunctionNames; - - public ReactiveCatalogImpl( - BlockingCatalog blockingCatalog, - @Qualifier("catalogScheduler") Scheduler catalogScheduler) { - this.blockingCatalog = blockingCatalog; - this.catalogScheduler = catalogScheduler; - } - - private Mono async(Callable callable) { - return Mono.fromCallable(callable).subscribeOn(catalogScheduler); - } - - private Mono async(Runnable runnable, T returnValue) { - return Mono.fromRunnable(runnable).subscribeOn(catalogScheduler).thenReturn(returnValue); - } - - @Override - public Mono create(@NonNull Mono info) { - return info.subscribeOn(catalogScheduler).map(blockingCatalog::add); - } - - public Mono update(@NonNull C info, @NonNull Mono patch) { - return patch.subscribeOn(catalogScheduler).map(p -> blockingCatalog.update(info, p)); - } - - @Override - public Mono delete(@NonNull C info) { - return Mono.just(info).subscribeOn(catalogScheduler).map(blockingCatalog::delete); - } - - @Override - public Flux getAll(@NonNull Class type) { - return query(Query.all(type)); - } - - @Override - public Mono getById(@NonNull String id, @NonNull Class type) { - - return async(() -> blockingCatalog.get(id, type)); - } - - @Override - public Mono getFirstByName( - @NonNull String name, @NonNull Class type) { - - return async(() -> blockingCatalog.getByName(name, type)); - } - - @Override - public Mono canSortBy(Class type, String propertyName) { - return async(() -> blockingCatalog.getFacade().canSort(type, propertyName)); - } - - @Override - public Flux query(@NonNull Query query) { - log.debug( - "Processing request query of {} with filter {}", - query.getType().getSimpleName(), - query.getFilter()); - return Flux.fromStream(() -> blockingCatalog.query(query)).subscribeOn(catalogScheduler); - } - - @Override - public Mono count( - @NonNull Class type, @NonNull Filter filter) { - - return async(() -> (long) blockingCatalog.count(type, filter)); - } - - @Override - public Flux getSupportedFunctionNames() { - return Flux.fromStream(this::supportedFunctionNames).subscribeOn(catalogScheduler); - } - - private Stream supportedFunctionNames() { - if (supportedFilterFunctionNames == null) { - List names = - new FunctionFinder(null) - .getAllFunctionDescriptions().stream() - .filter(this::supportsdArgumentTypes) - .sorted((f1, f2) -> f1.getName().compareTo(f2.getName())) - .collect(Collectors.toCollection(LinkedList::new)); - if (!names.contains(IsInstanceOf.NAME)) { - names.add(0, IsInstanceOf.NAME); - } - supportedFilterFunctionNames = names; - } - return supportedFilterFunctionNames.stream(); - } - - private boolean supportsdArgumentTypes(FunctionName fn) { - try { - List> args = fn.getArguments(); - for (Parameter p : args) { - Class type = p.getType(); - if (!isCommonParamType(type)) { - log.debug( - "FunctionName {} not supported, parameter type {} is not considered safe", - fn.getName(), - type.getCanonicalName()); - return false; - } - } - return true; - } catch (RuntimeException e) { - log.warn( - "Error figuring out of function {} is supported: {}", - fn.getName(), - e.getMessage()); - return false; - } - } - - /** Does it look like something we could send/receive over the wire? */ - private boolean isCommonParamType(Class type) { - if (type.isPrimitive()) return true; - return Arrays.asList( - Number.class, - Boolean.class, - CharSequence.class, - Date.class, - Geometry.class, - ReferencedEnvelope.class, - CoordinateReferenceSystem.class, - Class.class) - .stream() - .anyMatch(c -> c.isAssignableFrom(type)); - } - - @Override - public Mono setDefaultWorkspace(@NonNull WorkspaceInfo workspace) { - return async(() -> blockingCatalog.setDefaultWorkspace(workspace), workspace); - } - - @Override - public Mono unsetDefaultWorkspace() { - return getDefaultWorkspace().doOnSuccess(ns -> blockingCatalog.setDefaultWorkspace(null)); - } - - @Override - public Mono unsetDefaultNamespace() { - return getDefaultNamespace().doOnSuccess(ns -> blockingCatalog.setDefaultNamespace(null)); - } - - @Override - public Mono unsetDefaultDataStore(@NonNull WorkspaceInfo workspace) { - return getDefaultDataStore(workspace) - .doOnSuccess(ds -> blockingCatalog.setDefaultDataStore(workspace, null)); - } - - @Override - public Mono getDefaultWorkspace() { - return async(blockingCatalog::getDefaultWorkspace); - } - - @Override - public Mono setDefaultNamespace(@NonNull NamespaceInfo namespace) { - return async(() -> blockingCatalog.setDefaultNamespace(namespace), namespace); - } - - @Override - public Mono getDefaultNamespace() { - return async(blockingCatalog::getDefaultNamespace); - } - - @Override - public Mono getOneNamespaceByURI(@NonNull String uri) { - return Mono.just(uri).subscribeOn(catalogScheduler).map(blockingCatalog::getNamespaceByURI); - } - - @Override - public Flux getAllNamespacesByURI(@NonNull String uri) { - return Flux.just(uri) - .subscribeOn(catalogScheduler) - .map(blockingCatalog::getNamespacesByURI) - .flatMap(Flux::fromStream); - } - - @Override - public Flux getDefaultDataStores() { - return Flux.fromStream(blockingCatalog::getDefaultDataStores).subscribeOn(catalogScheduler); - } - - @Override - public Mono setDefaultDataStore( - @NonNull WorkspaceInfo workspace, @NonNull DataStoreInfo dataStore) { - return async(() -> blockingCatalog.setDefaultDataStore(workspace, dataStore), dataStore); - } - - @Override - public Mono getDefaultDataStore(@NonNull WorkspaceInfo workspace) { - return async(() -> blockingCatalog.getDefaultDataStore(workspace)); - } - - @Override - public Flux getStoresByWorkspace( - @NonNull WorkspaceInfo workspace, @NonNull Class type) { - - return Flux.fromStream(() -> blockingCatalog.getStoresByWorkspace(workspace, type).stream()) - .subscribeOn(catalogScheduler); - } - - @Override - public Mono getStoreByName( - @NonNull WorkspaceInfo workspace, @NonNull String name, Class type) { - - return async(() -> blockingCatalog.getStoreByName(workspace, name, type)); - } - - @Override - public Mono getResourceByName( - @NonNull NamespaceInfo namespace, @NonNull String name, @NonNull Class type) { - - return async(() -> blockingCatalog.getResourceByName(namespace, name, type)); - } - - @Override - public Flux getLayersWithStyle(@NonNull StyleInfo style) { - return Flux.fromStream(() -> blockingCatalog.getLayers(style).stream()) - .subscribeOn(catalogScheduler); - } - - @Override - public Flux getLayersByResource(@NonNull ResourceInfo resource) { - return Flux.fromStream(() -> blockingCatalog.getLayers(resource).stream()) - .subscribeOn(catalogScheduler); - } - - @Override - public Flux getLayerGroupsWithNoWoskspace() { - return Flux.fromStream( - () -> - blockingCatalog - .getLayerGroupsByWorkspace(CatalogFacade.NO_WORKSPACE) - .stream()) - .subscribeOn(catalogScheduler); - } - - @Override - public Flux getLayerGroupsByWoskspace(@NonNull WorkspaceInfo workspace) { - return Flux.fromStream(() -> blockingCatalog.getLayerGroupsByWorkspace(workspace).stream()) - .subscribeOn(catalogScheduler); - } - - @Override - public Mono getLayerGroupByName(@NonNull String name) { - return Mono.just(name) - .subscribeOn(catalogScheduler) - .map(blockingCatalog::getLayerGroupByName); - } - - @Override - public Mono getLayerGroupByName( - @NonNull WorkspaceInfo workspace, @NonNull String name) { - return async(() -> blockingCatalog.getLayerGroupByName(workspace, name)); - } - - @Override - public Flux getStylesWithNoWorkspace() { - return Flux.fromStream( - () -> - blockingCatalog - .getStylesByWorkspace(CatalogFacade.NO_WORKSPACE) - .stream()) - .subscribeOn(catalogScheduler); - } - - @Override - public Flux getStylesByWorkspace(@NonNull WorkspaceInfo workspace) { - return Flux.just(workspace) - .subscribeOn(catalogScheduler) - .map(blockingCatalog::getStylesByWorkspace) - .flatMap(Flux::fromIterable); - } - - @Override - public Mono getStyleByName(@NonNull WorkspaceInfo workspace, @NonNull String name) { - return async(() -> blockingCatalog.getStyleByName(workspace, name)); - } - - @Override - public Mono getStyleByName(@NonNull String name) { - return async(() -> blockingCatalog.getStyleByName(CatalogFacade.NO_WORKSPACE, name)); - } -} diff --git a/src/catalog/catalog-server/server/src/main/java/org/geoserver/cloud/catalog/server/service/ReactiveGeoServer.java b/src/catalog/catalog-server/server/src/main/java/org/geoserver/cloud/catalog/server/service/ReactiveGeoServer.java deleted file mode 100644 index 64a838b32..000000000 --- a/src/catalog/catalog-server/server/src/main/java/org/geoserver/cloud/catalog/server/service/ReactiveGeoServer.java +++ /dev/null @@ -1,206 +0,0 @@ -/* - * (c) 2020 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.cloud.catalog.server.service; - -import org.geoserver.catalog.WorkspaceInfo; -import org.geoserver.catalog.plugin.Patch; -import org.geoserver.config.GeoServer; -import org.geoserver.config.GeoServerInfo; -import org.geoserver.config.LoggingInfo; -import org.geoserver.config.ServiceInfo; -import org.geoserver.config.SettingsInfo; -import org.geoserver.ows.util.OwsUtils; -import org.geoserver.wcs.WCSInfo; -import org.geoserver.wfs.WFSInfo; -import org.geoserver.wms.WMSInfo; -import org.geoserver.wps.WPSInfo; -import org.springframework.beans.factory.annotation.Qualifier; -import org.springframework.stereotype.Service; - -import reactor.core.publisher.Flux; -import reactor.core.publisher.Mono; -import reactor.core.scheduler.Scheduler; - -import java.util.List; -import java.util.Objects; -import java.util.concurrent.Callable; - -/** */ -@Service -public class ReactiveGeoServer { - private Scheduler catalogScheduler; - - private GeoServer blockingConfig; - - public ReactiveGeoServer( // - GeoServer blockingConfig, // - @Qualifier("catalogScheduler") Scheduler catalogScheduler) { - - this.blockingConfig = blockingConfig; - this.catalogScheduler = catalogScheduler; - } - - private Mono async(Callable callable) { - return Mono.fromCallable(callable).subscribeOn(catalogScheduler); - } - - private Mono async(Runnable runnable) { - return Mono.fromRunnable(runnable).subscribeOn(catalogScheduler).then(); - } - - public Mono getGlobal() { - return async(() -> blockingConfig.getGlobal()); - } - - public Mono getLogging() { - return async(blockingConfig::getLogging); - } - - public Mono setGlobal(GeoServerInfo global) { - return async( - () -> { - GeoServerInfo local = blockingConfig.getGlobal(); - if (local == null) { - blockingConfig.setGlobal(global); - } else { - OwsUtils.copy(global, local, GeoServerInfo.class); - blockingConfig.save(local); - } - return blockingConfig.getGlobal(); - }); - } - - public Mono setLogging(LoggingInfo logging) { - return async( - () -> { - LoggingInfo local = blockingConfig.getLogging(); - if (local == null) { - blockingConfig.setLogging(logging); - } else { - OwsUtils.copy(logging, local, LoggingInfo.class); - blockingConfig.save(local); - } - return blockingConfig.getLogging(); - }); - } - - public Mono getSettingsByWorkspace(WorkspaceInfo workspace) { - return async(() -> blockingConfig.getSettings(workspace)); - } - - public Mono add(SettingsInfo settings) { - return async(() -> blockingConfig.add(settings)); - } - - public Mono add(ServiceInfo service) { - return async(() -> blockingConfig.add(service)); - } - - public Mono update(SettingsInfo settings, Patch patch) { - return async( - () -> { - patch.applyTo(settings, SettingsInfo.class); - blockingConfig.save(settings); - return settings; - }); - } - - public Mono remove(SettingsInfo settings) { - return async( - () -> { - blockingConfig.remove(settings); - }); - } - - public Mono remove(ServiceInfo service) { - return async( - () -> { - blockingConfig.remove(service); - }); - } - - public Mono save(ServiceInfo service) { - return async( - () -> { - ServiceInfo proxied = - blockingConfig.getService(service.getId(), ServiceInfo.class); - @SuppressWarnings("unchecked") - Class type = (Class) resolveClass(service.getClass()); - OwsUtils.copy(service, proxied, type); - blockingConfig.save(proxied); - }); - } - - public Mono update(ServiceInfo service, Patch patch) { - return async( - () -> { - Class serviceType = resolveClass(service.getClass()); - patch.applyTo(service, serviceType); - blockingConfig.save(service); - return service; - }); - } - - public Mono getSettingsById(String id) { - // TODO: improve - return async( - () -> { - List workspaces = blockingConfig.getCatalog().getWorkspaces(); - for (WorkspaceInfo w : workspaces) { - SettingsInfo settings = blockingConfig.getSettings(w); - if (settings != null && Objects.equals(id, settings.getId())) { - return settings; - } - } - return null; - }); - } - - public Mono getSettings(WorkspaceInfo workspace) { - return async(() -> blockingConfig.getSettings(workspace)); - } - - private Class resolveClass(Class serviceType) { - if (WMSInfo.class.isAssignableFrom(serviceType)) return WMSInfo.class; - if (WFSInfo.class.isAssignableFrom(serviceType)) return WFSInfo.class; - if (WCSInfo.class.isAssignableFrom(serviceType)) return WCSInfo.class; - if (WPSInfo.class.isAssignableFrom(serviceType)) return WPSInfo.class; - - return ServiceInfo.class; - } - - public Mono getServiceById(String id) { - return async(() -> blockingConfig.getService(id, ServiceInfo.class)); - } - - public Mono getGlobalService(Class type) { - return async(() -> blockingConfig.getService(type)); - } - - public Mono getGlobalServiceByName(String name) { - return async(() -> blockingConfig.getServiceByName(name, ServiceInfo.class)); - } - - public Flux getGlobalServices() { - return Flux.fromStream(() -> blockingConfig.getServices().stream()) - .subscribeOn(catalogScheduler); - } - - public Flux getServicesByWorkspace(WorkspaceInfo workspace) { - return Flux.fromStream(() -> blockingConfig.getServices(workspace).stream()) - .subscribeOn(catalogScheduler); - } - - public Mono getServiceByWorkspaceAndName( - WorkspaceInfo workspace, String serviceName) { - return async( - () -> blockingConfig.getServiceByName(workspace, serviceName, ServiceInfo.class)); - } - - public Mono getServiceByWorkspaceAndType( - WorkspaceInfo workspace, Class type) { - return async(() -> blockingConfig.getService(workspace, type)); - } -} diff --git a/src/catalog/catalog-server/server/src/main/java/org/geoserver/cloud/catalog/server/service/ReactiveResourceStore.java b/src/catalog/catalog-server/server/src/main/java/org/geoserver/cloud/catalog/server/service/ReactiveResourceStore.java deleted file mode 100644 index 851ed230f..000000000 --- a/src/catalog/catalog-server/server/src/main/java/org/geoserver/cloud/catalog/server/service/ReactiveResourceStore.java +++ /dev/null @@ -1,32 +0,0 @@ -/* - * (c) 2020 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.cloud.catalog.server.service; - -import lombok.NonNull; - -import org.geoserver.platform.resource.Resource; - -import reactor.core.publisher.Flux; -import reactor.core.publisher.Mono; - -import java.nio.ByteBuffer; - -/** */ -public interface ReactiveResourceStore { - - Mono get(String path); - - Mono getContents(String path); - - Mono remove(String path); - - Mono move(String path, String target); - - Flux list(Resource resource); - - Mono setContents(String path, ByteBuffer contents); - - Mono create(String path, @NonNull Resource.Type type); -} diff --git a/src/catalog/catalog-server/server/src/main/java/org/geoserver/cloud/catalog/server/service/ReactiveResourceStoreImpl.java b/src/catalog/catalog-server/server/src/main/java/org/geoserver/cloud/catalog/server/service/ReactiveResourceStoreImpl.java deleted file mode 100644 index 059892a98..000000000 --- a/src/catalog/catalog-server/server/src/main/java/org/geoserver/cloud/catalog/server/service/ReactiveResourceStoreImpl.java +++ /dev/null @@ -1,106 +0,0 @@ -/* - * (c) 2020 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.cloud.catalog.server.service; - -import lombok.NonNull; - -import org.geoserver.platform.resource.Resource; -import org.geoserver.platform.resource.Resource.Type; -import org.geoserver.platform.resource.ResourceStore; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Qualifier; -import org.springframework.stereotype.Service; - -import reactor.core.publisher.Flux; -import reactor.core.publisher.Mono; -import reactor.core.scheduler.Scheduler; - -import java.io.IOException; -import java.io.UncheckedIOException; -import java.nio.ByteBuffer; - -/** */ -@Service -public class ReactiveResourceStoreImpl implements ReactiveResourceStore { - - private @Autowired @Qualifier("resourceStoreImpl") ResourceStore blockingStore; - private @Autowired Scheduler catalogScheduler; - - @Override - public Mono get(String path) { - return Mono.just(path).subscribeOn(catalogScheduler).map(blockingStore::get); - } - - @Override - public Mono getContents(String path) { - return get(path) - .map( - r -> { - try { - return r.getContents(); - } catch (IOException e) { - e.printStackTrace(); - throw new UncheckedIOException(e); - } - }) - .map(ByteBuffer::wrap); - } - - @Override - public Mono setContents(String path, ByteBuffer contents) { - return get(path) - .map( - resource -> { - byte[] byteArray = new byte[contents.remaining()]; - contents.get(byteArray); - try { - resource.setContents(byteArray); - } catch (IOException e) { - throw new UncheckedIOException(e); - } - return resource; - }); - } - - @Override - public Mono remove(String path) { - return Mono.just(path).subscribeOn(catalogScheduler).map(blockingStore::remove); - } - - /** - * @return the new resource, or empty if it couldn't be moved - */ - @Override - public Mono move(String path, String target) { - return Mono.just(path) - .subscribeOn(catalogScheduler) - .map(source -> blockingStore.move(source, target)) - .flatMap(moved -> moved ? get(target) : Mono.empty()); - } - - @Override - public Flux list(Resource resource) { - return Mono.just(resource) - .subscribeOn(catalogScheduler) - .map(Resource::list) - .flatMapMany(l -> Flux.fromStream(l.stream())); - } - - @Override - public Mono create(String path, @NonNull Resource.Type type) { - return get(path) - .map( - r -> { - if (type == Type.DIRECTORY) { - r.dir(); - } else { - r.file(); - } - return r; - }) - .map(Resource::path) - .flatMap(this::get); - } -} diff --git a/src/catalog/catalog-server/server/src/main/resources/META-INF/spring.factories b/src/catalog/catalog-server/server/src/main/resources/META-INF/spring.factories deleted file mode 100644 index 3592c1fa1..000000000 --- a/src/catalog/catalog-server/server/src/main/resources/META-INF/spring.factories +++ /dev/null @@ -1,2 +0,0 @@ -org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ -org.geoserver.cloud.autoconfigure.catalog.server.CatalogServerAutoConfiguration \ No newline at end of file diff --git a/src/catalog/catalog-server/server/src/test/java/org/geoserver/cloud/catalog/server/api/v1/AbstractReactiveCatalogControllerTest.java b/src/catalog/catalog-server/server/src/test/java/org/geoserver/cloud/catalog/server/api/v1/AbstractReactiveCatalogControllerTest.java deleted file mode 100644 index 3462fd649..000000000 --- a/src/catalog/catalog-server/server/src/test/java/org/geoserver/cloud/catalog/server/api/v1/AbstractReactiveCatalogControllerTest.java +++ /dev/null @@ -1,329 +0,0 @@ -/* - * (c) 2020 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.cloud.catalog.server.api.v1; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertNotNull; -import static org.junit.jupiter.api.Assertions.assertNotSame; -import static org.junit.jupiter.api.Assertions.assertNull; - -import lombok.NonNull; - -import org.geoserver.catalog.Catalog; -import org.geoserver.catalog.CatalogInfo; -import org.geoserver.catalog.CatalogTestData; -import org.geoserver.catalog.impl.ClassMappings; -import org.geoserver.catalog.plugin.Query; -import org.geoserver.catalog.plugin.resolving.ProxyUtils; -import org.geoserver.cloud.catalog.server.test.CatalogTestClient; -import org.geoserver.cloud.catalog.server.test.TestConfiguration; -import org.geoserver.cloud.catalog.server.test.WebTestClientSupport; -import org.geoserver.cloud.catalog.server.test.WebTestClientSupportConfiguration; -import org.geoserver.config.GeoServer; -import org.geotools.api.filter.Filter; -import org.geotools.filter.text.cql2.CQLException; -import org.geotools.filter.text.ecql.ECQL; -import org.junit.jupiter.api.AfterEach; -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Qualifier; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.http.MediaType; -import org.springframework.test.context.ActiveProfiles; -import org.springframework.test.web.reactive.server.WebTestClient; - -import java.io.IOException; -import java.util.Arrays; -import java.util.List; -import java.util.Optional; -import java.util.Set; -import java.util.function.BiConsumer; -import java.util.function.Consumer; -import java.util.function.Function; -import java.util.stream.Collectors; - -import javax.annotation.Nullable; - -@SpringBootTest(classes = {TestConfiguration.class, WebTestClientSupportConfiguration.class}) -@ActiveProfiles("test") // see bootstrap-test.yml -public abstract class AbstractReactiveCatalogControllerTest { - - protected @Autowired WebTestClientSupport clientSupport; - - protected @Autowired @Qualifier("catalog") Catalog catalog; - protected @Autowired @Qualifier("geoServer") GeoServer geoServer; - - protected CatalogTestData testData; - - protected final @NonNull Class infoType; - - protected ProxyUtils proxyResolver; - - protected AbstractReactiveCatalogControllerTest(@NonNull Class infoType) { - this.infoType = infoType; - } - - public @BeforeEach void setup() { - proxyResolver = - new ProxyUtils(catalog, Optional.of(geoServer)).failOnMissingReference(true); - testData = - CatalogTestData.initialized(() -> catalog, () -> null) - .initConfig(false) - .initialize(); - } - - public @AfterEach void after() { - if (null != testData) testData.after(); - } - - public abstract @Test void testFindAll(); - - public abstract @Test void testFindAllByType(); - - public abstract @Test void testFindById(); - - public abstract @Test void testQueryFilter(); - - protected void testFindAll(@SuppressWarnings("unchecked") C... expected) { - Set expectedIds = - Arrays.stream(expected).map(CatalogInfo::getId).collect(Collectors.toSet()); - Set actual = - this.findAll().stream().map(CatalogInfo::getId).collect(Collectors.toSet()); - assertEquals(expectedIds, actual); - } - - protected void testFindAll( - Class type, @SuppressWarnings("unchecked") S... expected) { - Set expectedIds = - Arrays.stream(expected).map(CatalogInfo::getId).collect(Collectors.toSet()); - ClassMappings classMappings = ClassMappings.fromInterface(type); - Set actual = - this.findAll(classMappings).stream() - .map(CatalogInfo::getId) - .collect(Collectors.toSet()); - assertEquals(expectedIds, actual); - } - - protected void testQueryFilter( - String ecqlFilter, @SuppressWarnings("unchecked") S... expected) { - testQueryFilter(this.infoType, ecqlFilter, expected); - } - - protected void testQueryFilter( - Class type, String ecqlFilter, @SuppressWarnings("unchecked") S... expected) { - Filter filter; - try { - filter = ECQL.toFilter(ecqlFilter); - } catch (CQLException e) { - throw new RuntimeException(e); - } - this.testQueryFilter(type, filter, expected); - } - - protected void testQueryFilter( - @NonNull Class type, Filter filter, @SuppressWarnings("unchecked") S... expected) { - String endpoint = endpoint(); - - Query query = Query.valueOf(type, filter); - - client().doPost(query, "/{endpoint}/query", endpoint) - .expectStatus() - .isOk() - .expectHeader() - .contentType(MediaType.APPLICATION_STREAM_JSON) - .expectBodyList(type) - .consumeWith( - response -> { - List responseBody = response.getResponseBody(); - - Set expectedIds = - Arrays.stream(expected) - .map(CatalogInfo::getId) - .collect(Collectors.toSet()); - Set returnedIds = - responseBody.stream() - .map(CatalogInfo::getId) - .collect(Collectors.toSet()); - assertEquals(expectedIds, returnedIds); - }); - } - - protected void testFindById(C expected) { - C responseBody = - client().findById(expected) - .expectStatus() - .isOk() - .expectBody(infoType) - .returnResult() - .getResponseBody(); - C resolved = resolveProxies(responseBody); - assertCatalogInfoEquals(expected, resolved); - } - - protected I resolveProxies(I info) { - return proxyResolver.resolve(info); - } - - protected final void assertCatalogInfoEquals(C expected, C actual) { - assertPropertriesEqual(expected, actual); - } - - /** - * Subclasses should override to provide {@link CatalogInfo} subtype specific assertions. Not - * doing {@code assertEquals(expected, actual)} because the returned object may differ from the - * submitted one as the catalog populated default properties - */ - protected abstract void assertPropertriesEqual(C expected, C actual); - - protected CatalogTestClient client() { - return this.clientSupport.clientFor(infoType); - } - - protected WebTestClient webtTestClient() { - return this.clientSupport.get(); - } - - @Test - void testFindByIdNotFound() throws IOException { - client().findById("non-existent-ws-id", infoType).expectStatus().isNoContent(); - } - - protected String endpoint() { - return toEndpoint(ClassMappings.fromInterface(this.infoType)); - } - - protected String toEndpoint(ClassMappings cm) { - return cm.name().toLowerCase() + "s"; - } - - protected List findAll() { - return findAll(null); - } - - protected List findAll(@Nullable ClassMappings subType) { - String endpoint = endpoint(); - return client().getRelative("/{endpoint}?type={type}", endpoint, subType) - .expectStatus() - .isOk() - .expectHeader() - .contentType(MediaType.APPLICATION_STREAM_JSON) - .expectBodyList(infoType) - .returnResult() - .getResponseBody(); - } - - protected void crudTest( - final C toCreate, - Function catalogLookup, - Consumer modifyingConsumer, - BiConsumer updateVerifier) { - - C created = testCreate(toCreate, catalogLookup); - - C updated = testUpdate(created, modifyingConsumer, updateVerifier); - - testDelete(updated, catalogLookup); - } - - protected C testUpdate( - C created, Consumer modifyingConsumer, BiConsumer updateVerifier) { - final Class expectedType = expectedType(created); - C updated = - client().update(created, modifyingConsumer) - .expectStatus() - .isOk() - .expectBody(expectedType) - .returnResult() - .getResponseBody(); - assertNotSame(created, updated); - updated = resolveProxies(updated); - updateVerifier.accept(created, updated); - - C foundAfterUpdate = - client().findById(updated) - .expectStatus() - .isOk() - .expectBody(expectedType) - .returnResult() - .getResponseBody(); - foundAfterUpdate = resolveProxies(foundAfterUpdate); - updateVerifier.accept(created, foundAfterUpdate); - - return updated; - } - - protected C testCreate(C toCreate, Function catalogLookup) { - final @Nullable String providedId = toCreate.getId(); - - CatalogTestClient testClient = this.client(); - - assertNull( - catalogLookup.apply(toCreate.getId()), - "Object to be created shall not already exist in catalog"); - - final Class expectedType = expectedType(toCreate); - - C created = - testClient - .create(toCreate) - .expectStatus() - .isCreated() - .expectBody(expectedType) - .returnResult() - .getResponseBody(); - created = resolveProxies(created); - assertNotNull( - catalogLookup.apply(created.getId()), - "created object not found in service backend catalog"); - - assertNotSame(toCreate, created); - if (providedId == null) assertNotNull(created.getId()); - else assertEquals(providedId, created.getId()); - - assertCatalogInfoEquals(toCreate, created); - - testClient - .findById(created) - .expectStatus() - .isOk() - .expectBody(expectedType) - .consumeWith(Assertions::assertNotNull); - - // try to create it again? - /// testClient.create(toCreate).expectStatus().is; - return created; - } - - protected C testDelete(final C toDelete, Function catalogLookup) { - final Class expectedType = expectedType(toDelete); - - client().findById(toDelete).expectStatus().isOk(); - - C deleted = - client().delete(toDelete) - .expectStatus() - .isOk() - .expectBody(expectedType) - .returnResult() - .getResponseBody(); - assertNull( - catalogLookup.apply(toDelete.getId()), "object not deleted from backend catalog"); - - client().findById(deleted).expectStatus().isNoContent(); - - client().delete(toDelete).expectStatus().isNoContent(); - - return deleted; - } - - private Class expectedType(C info) { - @SuppressWarnings("unchecked") - final Class expectedType = - (Class) ClassMappings.fromImpl(info.getClass()).getInterface(); - return expectedType; - } -} diff --git a/src/catalog/catalog-server/server/src/test/java/org/geoserver/cloud/catalog/server/api/v1/LayerControllerTest.java b/src/catalog/catalog-server/server/src/test/java/org/geoserver/cloud/catalog/server/api/v1/LayerControllerTest.java deleted file mode 100644 index 72fbc7da4..000000000 --- a/src/catalog/catalog-server/server/src/test/java/org/geoserver/cloud/catalog/server/api/v1/LayerControllerTest.java +++ /dev/null @@ -1,224 +0,0 @@ -/* - * (c) 2020 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.cloud.catalog.server.api.v1; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertTrue; - -import com.google.common.collect.Sets; - -import org.geoserver.catalog.LayerInfo; -import org.geoserver.catalog.StyleInfo; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.springframework.boot.test.autoconfigure.web.reactive.AutoConfigureWebTestClient; -import org.springframework.http.MediaType; - -import java.util.Arrays; -import java.util.List; -import java.util.Set; -import java.util.stream.Collectors; - -@AutoConfigureWebTestClient(timeout = "360000") -class LayerControllerTest extends AbstractReactiveCatalogControllerTest { - - public LayerControllerTest() { - super(LayerInfo.class); - } - - protected @Override void assertPropertriesEqual(LayerInfo expected, LayerInfo actual) { - assertEquals(expected.getName(), actual.getName()); - assertEquals(expected.getResource().getId(), actual.getResource().getId()); - assertEquals(expected.getDefaultStyle(), actual.getDefaultStyle()); - assertEquals(expected.getStyles(), actual.getStyles()); - } - - public @BeforeEach void removeExisitng() { - // can't create the layer with testData.ft as its resource otherwise, it's a 1:1 - // relationship - catalog.remove(testData.layerGroup1); - catalog.remove(testData.layerFeatureTypeA); - } - - @Override - public @Test void testFindAll() { - assertTrue(super.findAll().isEmpty()); - LayerInfo layer1 = testData.layerFeatureTypeA; - LayerInfo layer2 = - testData.createLayer( - "cov-layer-id", - testData.coverageA, - "coverage layer", - true, - testData.style1); - - catalog.add(layer1); - super.testFindAll(layer1); - catalog.add(layer2); - super.testFindAll(layer1, layer2); - } - - @Override - public @Test void testFindAllByType() { - assertTrue(super.findAll().isEmpty()); - LayerInfo layer1 = testData.layerFeatureTypeA; - LayerInfo layer2 = - testData.createLayer( - "cov-layer-id", - testData.coverageA, - "coverage layer", - true, - testData.style1); - - catalog.add(layer1); - super.testFindAll(LayerInfo.class, layer1); - catalog.add(layer2); - super.testFindAll(LayerInfo.class, layer1, layer2); - } - - @Override - public @Test void testFindById() { - catalog.add(testData.layerFeatureTypeA); - super.testFindById(testData.layerFeatureTypeA); - } - - @Override - public @Test void testQueryFilter() { - catalog.add(testData.layerFeatureTypeA); - StyleInfo style1 = testData.style1; - StyleInfo style2 = testData.style2; - StyleInfo style3 = testData.createStyle("style3"); - StyleInfo style4 = testData.createStyle("style4"); - catalog.add(style3); - catalog.add(style4); - - LayerInfo layer1 = catalog.getLayer(testData.layerFeatureTypeA.getId()); - layer1.getStyles().add(style4); - layer1.getStyles().add(style2); - catalog.save(layer1); - LayerInfo layer2 = - testData.createLayer( - "cov-layer-id", - testData.coverageA, - "coverage layer", - true, - style2, - style1, - style3, - style4); - catalog.add(layer1); - catalog.add(layer2); - - String cql = String.format("\"defaultStyle.name\" = '%s'", style1.getName()); - super.testQueryFilter(cql, layer1); - - cql = String.format("\"styles.name\" = '%s'", style4.getName()); - super.testQueryFilter(cql, layer1, layer2); - } - - @Test - void testLayerCRUD() { - LayerInfo layer = testData.layerFeatureTypeA; - crudTest( - layer, - catalog::getLayer, - l -> { - l.setDefaultStyle(testData.style2); - }, - (orig, updated) -> { - assertEquals(testData.style2, updated.getDefaultStyle()); - }); - } - - @Test - void testUpdateStyles() { - LayerInfo layer = testData.layerFeatureTypeA; - catalog.add(layer); - - testUpdate( - layer, - l -> { - l.getStyles().clear(); - l.getStyles().add(testData.style1); - l.getStyles().add(testData.style2); - }, - (orig, updated) -> { - assertEquals(2, updated.getStyles().size()); - Set expected = Sets.newHashSet(testData.style2, testData.style1); - assertEquals(expected, updated.getStyles()); - }); - } - - @Test - void testFindLayersByResource() { - LayerInfo layer = testData.layerFeatureTypeA; - catalog.add(layer); - - String resourceId = layer.getResource().getId(); - client().getRelative("/layers/resource/{id}", resourceId) - .expectStatus() - .isOk() - .expectHeader() - .contentType(MediaType.APPLICATION_STREAM_JSON) - .expectBodyList(LayerInfo.class) - .consumeWith(res -> assertEquals(1, res.getResponseBody().size())); - } - - @Test - void testFindLayersByResource_NonExistentResourceId() { - client().getRelative("/layers/resource/{id}", "bad-resource-id") - .expectStatus() - .isNoContent(); - } - - @Test - void testFindLayersWithStyle() { - StyleInfo style1 = testData.style1; // on layer1 and layer2 - StyleInfo style2 = testData.style2; // layer2's default style - StyleInfo style3 = testData.createStyle("style3"); // on layer2 - StyleInfo style4 = testData.createStyle("styleWithNoLayerAssociated"); // on no layer - catalog.add(style3); - catalog.add(style4); - - LayerInfo layer1 = testData.layerFeatureTypeA; - LayerInfo layer2 = - testData.createLayer( - "cov-layer-id", - testData.coverageA, - "coverage layer", - true, - style2, - style1, - style3); - catalog.add(layer1); - catalog.add(layer2); - - testFindLayersWithStyle(style1, layer1, layer2); - testFindLayersWithStyle(style2, layer2); - testFindLayersWithStyle(style3, layer2); - testFindLayersWithStyle(style4); - } - - private void testFindLayersWithStyle(StyleInfo style, LayerInfo... expectedLayers) { - - client().getRelative("/layers/style/{styleId}", style.getId()) - .expectStatus() - .isOk() - .expectHeader() - .contentType(MediaType.APPLICATION_STREAM_JSON) - .expectBodyList(LayerInfo.class) - .consumeWith( - response -> { - List responseBody = response.getResponseBody(); - assertEquals( - Arrays.stream(expectedLayers) - .map(LayerInfo::getId) - .collect(Collectors.toSet()), - responseBody.stream() - .map(LayerInfo::getId) - .collect(Collectors.toSet())); - }); - } -} diff --git a/src/catalog/catalog-server/server/src/test/java/org/geoserver/cloud/catalog/server/api/v1/LayerGroupControllerTest.java b/src/catalog/catalog-server/server/src/test/java/org/geoserver/cloud/catalog/server/api/v1/LayerGroupControllerTest.java deleted file mode 100644 index 2785842e0..000000000 --- a/src/catalog/catalog-server/server/src/test/java/org/geoserver/cloud/catalog/server/api/v1/LayerGroupControllerTest.java +++ /dev/null @@ -1,158 +0,0 @@ -/* - * (c) 2020 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.cloud.catalog.server.api.v1; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertNull; - -import org.geoserver.catalog.LayerGroupInfo; -import org.geoserver.catalog.StyleInfo; -import org.geoserver.catalog.WorkspaceInfo; -import org.geotools.api.filter.Filter; -import org.junit.jupiter.api.Test; -import org.springframework.boot.test.autoconfigure.web.reactive.AutoConfigureWebTestClient; - -@AutoConfigureWebTestClient(timeout = "360000") -class LayerGroupControllerTest extends AbstractReactiveCatalogControllerTest { - - public LayerGroupControllerTest() { - super(LayerGroupInfo.class); - } - - protected @Override void assertPropertriesEqual( - LayerGroupInfo expected, LayerGroupInfo actual) { - assertEquals(expected.getWorkspace(), actual.getWorkspace()); - assertEquals(expected.getName(), actual.getName()); - assertEquals(expected.isAdvertised(), actual.isAdvertised()); - assertEquals(expected.getLayers(), actual.getLayers()); - } - - @Override - public @Test void testFindAll() { - super.testFindAll(testData.layerGroup1); - LayerGroupInfo lg2 = - testData.createLayerGroup( - "lg2", - testData.workspaceA, - "lg2", - testData.layerFeatureTypeA, - testData.style2); - catalog.add(lg2); - super.testFindAll(testData.layerGroup1, lg2); - } - - @Override - public @Test void testFindById() { - super.testFindById(testData.layerGroup1); - } - - @Override - public @Test void testFindAllByType() { - super.testFindAll(LayerGroupInfo.class, testData.layerGroup1); - } - - @Override - public @Test void testQueryFilter() { - LayerGroupInfo lg1 = testData.layerGroup1; - LayerGroupInfo lg2 = - testData.createLayerGroup( - "lg2", - testData.workspaceA, - "lg2", - testData.layerFeatureTypeA, - testData.style2); - catalog.add(lg2); - - super.testQueryFilter(LayerGroupInfo.class, Filter.INCLUDE, lg1, lg2); - super.testQueryFilter(LayerGroupInfo.class, Filter.EXCLUDE); - - String cql = String.format("\"workspace.name\" = '%s'", testData.workspaceA.getName()); - super.testQueryFilter(cql, lg2); - - cql = "\"workspace.name\" IS NULL"; - super.testQueryFilter(cql, lg1); - } - - @Test - void testLayerGroupCRUD_NoWorkspace() { - WorkspaceInfo workspace = null; - LayerGroupInfo layerGroup = - testData.createLayerGroup( - "layerGroupCRUD_NoWorkspace", - workspace, - "layerGroupCRUD_NoWorkspace_name", - testData.layerFeatureTypeA, - testData.style2); - crudTest( - layerGroup, - catalog::getLayerGroup, - lg -> { - lg.setEnabled(false); - lg.setTitle("changed title"); - lg.setAbstract("new abstract"); - lg.setAdvertised(false); - }, - (orig, updated) -> { - assertFalse(updated.isEnabled()); - assertFalse(updated.isAdvertised()); - assertEquals("changed title", updated.getTitle()); - assertEquals("new abstract", updated.getAbstract()); - assertEquals(1, orig.getLayers().size()); - assertEquals(1, updated.getLayers().size()); - }); - } - - @Test - void testLayerGroupCRUD_Workspace() { - final WorkspaceInfo workspace = testData.workspaceA; - LayerGroupInfo layerGroup = - testData.createLayerGroup( - "layerGroupCRUD_Workspace", - workspace, - "layerGroupCRUD_Workspace_name", - testData.layerFeatureTypeA, - (StyleInfo) null); - crudTest( - layerGroup, - catalog::getLayerGroup, - lg -> { - lg.getStyles().set(0, testData.style1); - }, - (orig, updated) -> { - assertNull(orig.getStyles().get(0)); - assertEquals(testData.style1, updated.getStyles().get(0)); - }); - } - - @Test - void testUpdateLayers() { - WorkspaceInfo workspace = null; - LayerGroupInfo layerGroup = - testData.createLayerGroup( - "layerGroupCRUD_NoWorkspace", - workspace, - "layerGroupCRUD_NoWorkspace_name", - testData.layerFeatureTypeA, - testData.style2); - crudTest( - layerGroup, - catalog::getLayerGroup, - lg -> { - lg.setEnabled(false); - lg.setTitle("changed title"); - lg.setAbstract("new abstract"); - lg.setAdvertised(false); - }, - (orig, updated) -> { - assertFalse(updated.isEnabled()); - assertFalse(updated.isAdvertised()); - assertEquals("changed title", updated.getTitle()); - assertEquals("new abstract", updated.getAbstract()); - assertEquals(1, orig.getLayers().size()); - assertEquals(1, updated.getLayers().size()); - }); - } -} diff --git a/src/catalog/catalog-server/server/src/test/java/org/geoserver/cloud/catalog/server/api/v1/NamespaceControllerTest.java b/src/catalog/catalog-server/server/src/test/java/org/geoserver/cloud/catalog/server/api/v1/NamespaceControllerTest.java deleted file mode 100644 index de194259d..000000000 --- a/src/catalog/catalog-server/server/src/test/java/org/geoserver/cloud/catalog/server/api/v1/NamespaceControllerTest.java +++ /dev/null @@ -1,230 +0,0 @@ -/* - * (c) 2020 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.cloud.catalog.server.api.v1; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertNotNull; -import static org.junit.jupiter.api.Assertions.assertTrue; -import static org.springframework.http.MediaType.APPLICATION_JSON; -import static org.springframework.http.MediaType.APPLICATION_STREAM_JSON; - -import org.geoserver.catalog.NamespaceInfo; -import org.junit.jupiter.api.Test; -import org.springframework.boot.test.autoconfigure.web.reactive.AutoConfigureWebTestClient; - -import java.io.IOException; -import java.util.List; - -@AutoConfigureWebTestClient(timeout = "360000") -class NamespaceControllerTest extends AbstractReactiveCatalogControllerTest { - - public NamespaceControllerTest() { - super(NamespaceInfo.class); - } - - protected @Override void assertPropertriesEqual(NamespaceInfo expected, NamespaceInfo actual) { - assertEquals(expected.getName(), actual.getName()); - assertEquals(expected.getPrefix(), actual.getPrefix()); - assertEquals(expected.getURI(), actual.getURI()); - } - - @Override - public @Test void testFindAll() { - super.testFindAll(testData.namespaceA, testData.namespaceB, testData.namespaceC); - } - - @Override - public @Test void testFindAllByType() { - super.testFindAll( - NamespaceInfo.class, testData.namespaceA, testData.namespaceB, testData.namespaceC); - } - - @Override - public @Test void testFindById() { - super.testFindById(testData.namespaceA); - super.testFindById(testData.namespaceB); - super.testFindById(testData.namespaceC); - } - - @Override - public @Test void testQueryFilter() { - NamespaceInfo ns1 = catalog.getNamespace(testData.namespaceA.getId()); - NamespaceInfo ns2 = catalog.getNamespace(testData.namespaceB.getId()); - NamespaceInfo ns3 = catalog.getNamespace(testData.namespaceC.getId()); - - super.testQueryFilter(String.format("URI = '%s'", ns2.getURI()), ns2); - - ns3.setIsolated(true); - ns3.setURI(ns1.getURI()); - catalog.save(ns3); - - super.testQueryFilter(String.format("URI = '%s'", ns1.getURI()), ns1, ns3); - } - - @Test - void testFindNamespaceById() { - testFindById(testData.namespaceA); - testFindById(testData.namespaceB); - testFindById(testData.namespaceC); - } - - @Test - void testFindNamespacePrefix() { - testFindByPrefix(testData.namespaceA); - testFindByPrefix(testData.namespaceB); - testFindByPrefix(testData.namespaceC); - } - - private void testFindByPrefix(NamespaceInfo expected) { - assertEquals(expected, client().getFirstByName(expected.getPrefix())); - } - - @Test - void testNamespaceInfo_CRUD() throws IOException { - NamespaceInfo ns = testData.faker().namespace(); - crudTest( - ns, - catalog::getNamespace, - n -> n.setPrefix("modified-prefix"), - (old, updated) -> assertEquals("modified-prefix", updated.getPrefix())); - } - - @Test - void testSetDefaultNamespace() { - assertEquals(testData.namespaceA, catalog.getDefaultNamespace()); - - NamespaceInfo returned = - client().put("/namespaces/default/{id}", testData.namespaceB.getId()) - .expectStatus() - .isOk() - .expectHeader() - .contentType(APPLICATION_JSON) - .expectBody(NamespaceInfo.class) - .returnResult() - .getResponseBody(); - - assertEquals(testData.namespaceB, returned); - } - - @Test - void testSetDefaultNamespaceNonExistent() { - assertEquals(testData.namespaceA, catalog.getDefaultNamespace()); - - client().put("/namespaces/default/{id}", "non-existent-id") - .expectStatus() - .isNoContent() - .expectHeader() - .contentType(APPLICATION_JSON); - } - - @Test - void testGetDefaultNamespace() { - NamespaceInfo returned = - client().getRelative("/namespaces/default") - .expectStatus() - .isOk() - .expectHeader() - .contentType(APPLICATION_JSON) - .expectBody(NamespaceInfo.class) - .returnResult() - .getResponseBody(); - - assertEquals(testData.namespaceA, returned); - catalog.setDefaultNamespace(testData.namespaceB); - - returned = - client().getRelative("/namespaces/default") - .expectStatus() - .isOk() - .expectHeader() - .contentType(APPLICATION_JSON) - .expectBody(NamespaceInfo.class) - .returnResult() - .getResponseBody(); - - assertEquals(testData.namespaceB, returned); - } - - @Test - void testGetDefaultNamespaceNoDefaultExists() { - testData.deleteAll(); - client().getRelative("/namespaces/default") - .expectStatus() - .isNoContent() - .expectHeader() - .contentType(APPLICATION_JSON); - } - - @Test - void testFindOneNamespaceByURI() { - NamespaceInfo ns1 = testData.namespaceA; - NamespaceInfo ns2 = - testData.faker().namespace("second-ns-with-duplicate-uri", "prefix2", ns1.getURI()); - ns2.setIsolated(true); - catalog.add(ns2); - - NamespaceInfo found = findByURI(ns1.getURI()); - // catalog.getNamespaceByURI() contract says it returns the first found with that uri... - assertTrue(found.getId().equals(ns1.getId()) || found.getId().equals(ns2.getId())); - } - - protected NamespaceInfo findByURI(String uri) { - NamespaceInfo found = - client().getRelative("/namespaces/uri?uri={uri}", uri) - .expectStatus() - .isOk() - .expectHeader() - .contentType(APPLICATION_JSON) - .expectBody(NamespaceInfo.class) - .returnResult() - .getResponseBody(); - return found; - } - - @Test - void testFindAllNamespacesByURI() { - NamespaceInfo ns1 = testData.namespaceA; - NamespaceInfo ns2 = - testData.faker().namespace("second-ns-with-duplicate-uri", "prefix2", ns1.getURI()); - ns2.setIsolated(true); - catalog.add(ns2); - - List found = - client().getRelative("/namespaces/uri/all?uri={uri}", ns1.getURI()) - .expectStatus() - .isOk() - .expectHeader() - .contentType(APPLICATION_STREAM_JSON) - .expectBodyList(NamespaceInfo.class) - .returnResult() - .getResponseBody(); - - assertTrue(found.contains(ns1)); - assertTrue(found.contains(ns2)); - assertEquals(2, found.size()); - } - - @Test - void testCreateNamespaceDuplicateURI() { - NamespaceInfo ns1 = testData.namespaceA; - NamespaceInfo ns2 = - testData.faker().namespace("second-ns-with-duplicate-uri", "prefix2", ns1.getURI()); - client().create(ns2).expectStatus().isBadRequest(); - - ns2.setIsolated(true); - NamespaceInfo created = - client().create(ns2) - .expectStatus() - .isCreated() - .expectHeader() - .contentType(APPLICATION_JSON) - .expectBody(NamespaceInfo.class) - .returnResult() - .getResponseBody(); - assertNotNull(created.getId()); - assertEquals(ns2.getPrefix(), created.getPrefix()); - assertEquals(ns1.getURI(), created.getURI()); - } -} diff --git a/src/catalog/catalog-server/server/src/test/java/org/geoserver/cloud/catalog/server/api/v1/ReactiveConfigControllerTest.java b/src/catalog/catalog-server/server/src/test/java/org/geoserver/cloud/catalog/server/api/v1/ReactiveConfigControllerTest.java deleted file mode 100644 index 6fb44507f..000000000 --- a/src/catalog/catalog-server/server/src/test/java/org/geoserver/cloud/catalog/server/api/v1/ReactiveConfigControllerTest.java +++ /dev/null @@ -1,676 +0,0 @@ -/* - * (c) 2020 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.cloud.catalog.server.api.v1; - -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.equalTo; -import static org.hamcrest.Matchers.instanceOf; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertNotNull; -import static org.junit.jupiter.api.Assertions.assertNull; -import static org.springframework.http.MediaType.APPLICATION_JSON; -import static org.springframework.http.MediaType.APPLICATION_STREAM_JSON; - -import org.geoserver.catalog.CatalogTestData; -import org.geoserver.catalog.Info; -import org.geoserver.catalog.WorkspaceInfo; -import org.geoserver.catalog.impl.MetadataLinkInfoImpl; -import org.geoserver.catalog.impl.ModificationProxy; -import org.geoserver.catalog.plugin.Patch; -import org.geoserver.catalog.plugin.PropertyDiff; -import org.geoserver.cloud.catalog.server.config.CatalogServerConfiguration; -import org.geoserver.cloud.catalog.server.test.WebTestClientSupportConfiguration; -import org.geoserver.config.GeoServer; -import org.geoserver.config.GeoServerInfo; -import org.geoserver.config.LoggingInfo; -import org.geoserver.config.ServiceInfo; -import org.geoserver.config.SettingsInfo; -import org.geoserver.wcs.WCSInfo; -import org.geoserver.wfs.WFSInfo; -import org.geoserver.wms.WMSInfo; -import org.geoserver.wps.WPSInfo; -import org.hamcrest.Matchers; -import org.junit.jupiter.api.AfterEach; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.mockito.Mockito; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Qualifier; -import org.springframework.boot.test.autoconfigure.web.reactive.AutoConfigureWebTestClient; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.boot.test.mock.mockito.SpyBean; -import org.springframework.test.context.ActiveProfiles; -import org.springframework.test.web.reactive.server.WebTestClient; -import org.springframework.test.web.reactive.server.WebTestClient.ResponseSpec; - -import java.util.Arrays; -import java.util.Set; -import java.util.stream.Collectors; - -@SpringBootTest( - classes = {CatalogServerConfiguration.class, WebTestClientSupportConfiguration.class}) -@ActiveProfiles("test") // see bootstrap-test.yml -@AutoConfigureWebTestClient(timeout = "360000") -class ReactiveConfigControllerTest { - - private @Autowired WebTestClient testClient; - - protected @SpyBean @Qualifier("geoServer") GeoServer geoServer; - - protected @Autowired ReactiveConfigController controller; - - private final String baseURI = ReactiveConfigController.BASE_URI; - - private CatalogTestData testData; - - public @BeforeEach void before() { - testData = - CatalogTestData.empty(() -> geoServer.getCatalog(), () -> geoServer).initialize(); - geoServer.getCatalog().add(testData.workspaceA); - geoServer.getCatalog().add(testData.workspaceB); - } - - public @AfterEach void after() { - testData.deleteAll(geoServer.getCatalog()); - WorkspaceInfo workspace = testData.workspaceA; - SettingsInfo settings = geoServer.getSettings(workspace); - if (settings != null) geoServer.remove(settings); - - geoServer.getServices().forEach(geoServer::remove); - geoServer.getServices(workspace).forEach(geoServer::remove); - } - - // GET /global - @Test - void getGlobal() { - GeoServerInfo global = controller.getGlobal().block(); - assertNotNull(global); - GeoServerInfo responseBody = - get("/global") - .expectStatus() - .isOk() - .expectBody(GeoServerInfo.class) - .returnResult() - .getResponseBody(); - assertEquals(global, responseBody); - - Mockito.doReturn(null).when(geoServer).getGlobal(); - - assertNull(geoServer.getGlobal()); - get("/global").expectStatus().isNoContent(); - } - - // PUT /global - @Test - void setGlobal() { - GeoServerInfo newGlobal = testData.global; - newGlobal.setAdminPassword("testme"); - newGlobal.setAdminUsername("me"); - newGlobal.getSettings().setCharset("ISO-8859-1"); - newGlobal.getSettings().setTitle("title set through api"); - - put(newGlobal, "/global").expectStatus().isOk().expectBody(GeoServerInfo.class); - - GeoServerInfo returned = geoServer.getGlobal(); - assertEquals("testme", returned.getAdminPassword()); - assertEquals("me", returned.getAdminUsername()); - assertEquals(newGlobal.getSettings(), returned.getSettings()); - } - - // GET /workspaces/{workspaceId}/settings - @Test - void getSettingsByWorkspace() { - WorkspaceInfo workspace = testData.workspaceA; - - get("/workspaces/{workspaceId}/settings", workspace.getId()).expectStatus().isNoContent(); - - SettingsInfo settings = testData.workspaceASettings; - settings.setWorkspace(workspace); - geoServer.add(settings); - - final SettingsInfo expected = geoServer.getSettings(workspace); - get("/workspaces/{workspaceId}/settings", workspace.getId()) - .expectStatus() - .isOk() - .expectBody(SettingsInfo.class) - .consumeWith(result -> assertEquals(expected, result.getResponseBody())); - } - - // POST /workspaces/{workspaceId}/settings - @Test - void createSettings() { - WorkspaceInfo workspace = testData.workspaceA; - assertNull(geoServer.getSettings(workspace)); - SettingsInfo settings = testData.workspaceASettings; - settings.setWorkspace(null); // should work even if workspace is not set beforehand - post(settings, "/workspaces/{workspaceId}/settings", workspace.getId()) - .expectStatus() - .isCreated(); - - assertNotNull(geoServer.getSettings(workspace)); - } - - // PATCH /workspaces/{workspaceId}/settings - @Test - void updateSettings() { - WorkspaceInfo workspace = testData.workspaceA; - SettingsInfo settings = testData.workspaceASettings; - settings.setWorkspace(workspace); - geoServer.add(settings); - settings = geoServer.getSettings(workspace); - - settings.setTitle("new title set through api"); - Patch patch = PropertyDiff.valueOf(ModificationProxy.handler(settings)).toPatch(); - - patch(patch, "/workspaces/{workspaceId}/settings", workspace.getId()) - .expectStatus() - .isOk() - .expectBody(SettingsInfo.class) - .value(s -> s.getTitle(), equalTo("new title set through api")); - assertEquals(settings.getTitle(), geoServer.getSettings(workspace).getTitle()); - } - - // DELETE /workspaces/{workspaceId}/settings - @Test - void deleteSettings() { - WorkspaceInfo workspace = testData.workspaceA; - SettingsInfo settings = testData.workspaceASettings; - settings.setWorkspace(workspace); - geoServer.add(settings); - assertNotNull(geoServer.getSettings(workspace)); - delete("/workspaces/{workspaceId}/settings", workspace.getId()) - .expectStatus() - .isOk() - .expectBody() - .isEmpty(); - assertNull(geoServer.getSettings(workspace)); - delete("/workspaces/{workspaceId}/settings", workspace.getId()) - .expectStatus() - .isNoContent(); - } - - // get /logging - @Test - void getLogging() { - geoServer.setLogging(testData.logging); - LoggingInfo logging = geoServer.getLogging(); - assertNotNull(logging); - LoggingInfo responseBody = - get("/logging") - .expectStatus() - .isOk() - .expectBody(LoggingInfo.class) - .returnResult() - .getResponseBody(); - assertEquals(logging, responseBody); - } - - // PUT /logging - @Test - void setLogging() { - LoggingInfo logging = testData.logging; - logging.setLevel("apiLevel"); - logging.setLocation("/right/there"); - logging.setStdOutLogging(false); - - put(logging, "/logging").expectStatus().isOk().expectBody(LoggingInfo.class); - assertEquals(logging, geoServer.getLogging()); - } - - // POST /services - @Test - void createService() { - if (null != geoServer.getService(WMSInfo.class)) - geoServer.remove(geoServer.getService(WMSInfo.class)); - - assertNull(geoServer.getService(WMSInfo.class)); - - WMSInfo service = testData.wmsService; - service.setWorkspace(null); - service.setTitle("created from api"); - post(service, "/services").expectStatus().isCreated().expectBody().isEmpty(); - WMSInfo stored = geoServer.getService(WMSInfo.class); - assertNotNull(stored); - assertEquals(service.getTitle(), stored.getTitle()); - } - - // POST /workspaces/{workspaceId}/services - @Test - void createServiceByWorkspace() { - WorkspaceInfo workspace = testData.workspaceA; - if (null != geoServer.getService(workspace, WMSInfo.class)) - geoServer.remove(geoServer.getService(workspace, WMSInfo.class)); - assertNull(geoServer.getService(workspace, WMSInfo.class)); - - WMSInfo service = testData.wmsService; - service.setWorkspace(null); // should work regardless - service.setTitle("created from api for workspace"); - post(service, "/workspaces/{workspaceId}/services", workspace.getId()) - .expectStatus() - .isCreated() - .expectBody() - .isEmpty(); - - WMSInfo stored = geoServer.getService(workspace, WMSInfo.class); - assertNotNull(stored); - assertEquals(service.getTitle(), stored.getTitle()); - } - - // DELETE /services/{serviceId} - @Test - void deleteServiceById() { - WMSInfo service = testData.wmsService; - if (null == geoServer.getService(WMSInfo.class)) geoServer.add(service); - assertNotNull(geoServer.getService(WMSInfo.class)); - - delete("/services/{serviceId}", service.getId()) - .expectStatus() - .isOk() - .expectBody() - .isEmpty(); - - assertNull(geoServer.getService(WMSInfo.class)); - } - - // GET /services/{serviceId} - @Test - void getServiceById() { - WorkspaceInfo ws = testData.workspaceA; - WMSInfo wmsService = testData.wmsService; - WCSInfo wcsService = testData.wcsService; - WFSInfo wfsService = testData.wfsService; - WPSInfo wpsService = testData.wpsService; - - wfsService.setWorkspace(ws); - wpsService.setWorkspace(ws); - - geoServer.add(wmsService); - geoServer.add(wcsService); - geoServer.add(wfsService); - geoServer.add(wpsService); - - get("/services/{serviceId}", wmsService.getId()) - .expectStatus() - .isOk() - .expectBody(WMSInfo.class) - .value(s -> s.getId(), Matchers.equalTo(wmsService.getId())); - get("/services/{serviceId}", wcsService.getId()) - .expectStatus() - .isOk() - .expectBody(WCSInfo.class) - .value(s -> s.getId(), Matchers.equalTo(wcsService.getId())); - get("/services/{serviceId}", wfsService.getId()) - .expectStatus() - .isOk() - .expectBody(WFSInfo.class) - .value(s -> s.getId(), Matchers.equalTo(wfsService.getId())); - get("/services/{serviceId}", wpsService.getId()) - .expectStatus() - .isOk() - .expectBody(WPSInfo.class) - .value(s -> s.getId(), Matchers.equalTo(wpsService.getId())); - } - - // PATCH /services/{id} - @Test - void updateService() { - geoServer.add(testData.wmsService); - geoServer.add(testData.wcsService); - geoServer.add(testData.wfsService); - geoServer.add(testData.wpsService); - WMSInfo wmsService = geoServer.getService(WMSInfo.class); - WCSInfo wcsService = geoServer.getService(WCSInfo.class); - WFSInfo wfsService = geoServer.getService(WFSInfo.class); - WPSInfo wpsService = geoServer.getService(WPSInfo.class); - testUpdateService(wcsService); - testUpdateService(wmsService); - testUpdateService(wfsService); - testUpdateService(wpsService); - } - - // PATCH /services/{id} - @Test - void updateServiceByWorkspace() { - addServicesToWorkspaceA(); - WorkspaceInfo ws = testData.workspaceA; - - WMSInfo wmsService = geoServer.getService(ws, WMSInfo.class); - WCSInfo wcsService = geoServer.getService(ws, WCSInfo.class); - WFSInfo wfsService = geoServer.getService(ws, WFSInfo.class); - WPSInfo wpsService = geoServer.getService(ws, WPSInfo.class); - - assertEquals(ws.getId(), testUpdateService(wcsService).getWorkspace().getId()); - assertEquals(ws.getId(), testUpdateService(wmsService).getWorkspace().getId()); - assertEquals(ws.getId(), testUpdateService(wfsService).getWorkspace().getId()); - assertEquals(ws.getId(), testUpdateService(wpsService).getWorkspace().getId()); - } - - private S testUpdateService(S service) { - service.setTitle("title updated"); - MetadataLinkInfoImpl metadataLink = new MetadataLinkInfoImpl(); - metadataLink.setAbout("md about"); - metadataLink.setContent("http://test.com/md-" + service.getId() + ".xml"); - metadataLink.setId(service.getId() + "-md-id"); - metadataLink.setMetadataType("testmd"); - metadataLink.setType("test"); - service.setMetadataLink(metadataLink); - - Patch patch = asPatch(service); - ServiceInfo returned = - patch(patch, "/services/{id}", service.getId()) - .expectStatus() - .isOk() - .expectBody(ServiceInfo.class) - .returnResult() - .getResponseBody(); - - @SuppressWarnings("unchecked") - Class origType = (Class) ModificationProxy.unwrap(service).getClass(); - assertThat(returned, instanceOf(origType)); - assertEquals(metadataLink, returned.getMetadataLink()); - assertEquals("title updated", returned.getTitle()); - return origType.cast(returned); - } - - private Patch asPatch(Info modified) { - ModificationProxy handler = ModificationProxy.handler(modified); - Patch patch = PropertyDiff.valueOf(handler).toPatch(); - return patch; - } - - // GET /workspaces/{workspaceId}/services - @Test - void getServicesByWorkspace() { - WorkspaceInfo ws = testData.workspaceA; - geoServer.getServices(ws).forEach(geoServer::remove); - - get("/workspaces/{workspaceId}/services", ws.getId()) - .expectStatus() - .isOk() - .expectHeader() - .contentType(APPLICATION_STREAM_JSON) - .expectStatus() - .isOk() - .expectBody() - .isEmpty(); - - testData.wmsService.setWorkspace(ws); - geoServer.add(testData.wmsService); - testGetServicesByWorkspace(ws, testData.wmsService); - - testData.wfsService.setWorkspace(ws); - geoServer.add(testData.wfsService); - testGetServicesByWorkspace(ws, testData.wmsService, testData.wfsService); - - testData.wcsService.setWorkspace(ws); - geoServer.add(testData.wcsService); - testGetServicesByWorkspace( - ws, testData.wmsService, testData.wfsService, testData.wcsService); - - testData.wpsService.setWorkspace(ws); - geoServer.add(testData.wpsService); - testGetServicesByWorkspace( - ws, - testData.wmsService, - testData.wfsService, - testData.wcsService, - testData.wpsService); - } - - private void testGetServicesByWorkspace(WorkspaceInfo ws, ServiceInfo... expected) { - - Set expectedIds = - Arrays.stream(expected).map(ServiceInfo::getId).collect(Collectors.toSet()); - - get("/workspaces/{workspaceId}/services", ws.getId()) - .expectStatus() - .isOk() - .expectHeader() - .contentType(APPLICATION_STREAM_JSON) - .expectBodyList(ServiceInfo.class) - .value( - l -> l.stream().map(ServiceInfo::getId).collect(Collectors.toSet()), - Matchers.equalTo(expectedIds)); - } - - // GET /services - @Test - void getGlobalServices() { - geoServer.getServices().forEach(geoServer::remove); - - get("/services") - .expectStatus() - .isOk() - .expectHeader() - .contentType(APPLICATION_STREAM_JSON) - .expectStatus() - .isOk() - .expectBody() - .isEmpty(); - - geoServer.add(testData.wmsService); - testGetServices(testData.wmsService); - - geoServer.add(testData.wfsService); - testGetServices(testData.wmsService, testData.wfsService); - - geoServer.add(testData.wcsService); - testGetServices(testData.wmsService, testData.wfsService, testData.wcsService); - - geoServer.add(testData.wpsService); - testGetServices( - testData.wmsService, testData.wfsService, testData.wcsService, testData.wpsService); - } - - private void testGetServices(ServiceInfo... expected) { - - Set expectedIds = - Arrays.stream(expected).map(ServiceInfo::getId).collect(Collectors.toSet()); - - get("/services") - .expectStatus() - .isOk() - .expectHeader() - .contentType(APPLICATION_STREAM_JSON) - .expectBodyList(ServiceInfo.class) - .value( - l -> l.stream().map(ServiceInfo::getId).collect(Collectors.toSet()), - Matchers.equalTo(expectedIds)); - } - - // GET @GetMapping("/services/type/{type} - @Test - void getGlobalService() { - testGetGlobalService(testData.wmsService, WMSInfo.class); - testGetGlobalService(testData.wfsService, WFSInfo.class); - testGetGlobalService(testData.wcsService, WCSInfo.class); - testGetGlobalService(testData.wpsService, WPSInfo.class); - } - - private void testGetGlobalService(S service, Class type) { - S existing = geoServer.getService(type); - if (existing != null) geoServer.remove(existing); - - String typeName = type.getName(); - get("/services/type/{type}", typeName).expectStatus().isNoContent(); - geoServer.add(service); - get("/services/type/{type}", typeName) - .expectStatus() - .isOk() - .expectBody(type) - .value(s -> s.getId(), equalTo(service.getId())); - } - - // @GetMapping("/workspaces/{workspaceId}/services/type/{type}") - @Test - void getServiceByWorkspaceAndType() { - WorkspaceInfo ws = testData.workspaceA; - geoServer.getServices(ws).forEach(geoServer::remove); - testGetServiceByWorkspaceAndType(ws, WMSInfo.class, testData.wmsService); - testGetServiceByWorkspaceAndType(ws, WFSInfo.class, testData.wfsService); - testGetServiceByWorkspaceAndType(ws, WCSInfo.class, testData.wcsService); - testGetServiceByWorkspaceAndType(ws, WPSInfo.class, testData.wpsService); - } - - private void testGetServiceByWorkspaceAndType( - WorkspaceInfo ws, Class type, S service) { - - String workspaceId = ws.getId(); - String typeParam = type.getName(); - - get("/workspaces/{workspaceId}/services/type/{type}", workspaceId, typeParam) - .expectStatus() - .isNoContent() - .expectHeader() - .contentType(APPLICATION_JSON); - - service.setWorkspace(ws); - geoServer.add(service); - - get("/workspaces/{workspaceId}/services/type/{type}", workspaceId, typeParam) - .expectStatus() - .isOk() - .expectHeader() - .contentType(APPLICATION_JSON) - .expectBody(type) - .value(ServiceInfo::getId, equalTo(service.getId())); - } - - // GET /services/name/{name} - @Test - void getGlobalServiceByName() { - geoServer.getServices().forEach(geoServer::remove); - testGetGlobalServiceByName(testData.wmsService); - testGetGlobalServiceByName(testData.wfsService); - testGetGlobalServiceByName(testData.wcsService); - testGetGlobalServiceByName(testData.wpsService); - } - - private void testGetGlobalServiceByName(ServiceInfo service) { - - final String name = service.getName(); - - get("/services/name/{name}", name) - .expectHeader() - .contentType(APPLICATION_JSON) - .expectStatus() - .isNoContent(); - - geoServer.add(service); - - get("/services/name/{name}", name) - .expectStatus() - .isOk() - .expectHeader() - .contentType(APPLICATION_JSON) - .expectBody(ServiceInfo.class) - .value(ServiceInfo::getId, equalTo(service.getId())) - .value(ServiceInfo::getName, equalTo(service.getName())); - - service = geoServer.getService(service.getId(), ServiceInfo.class); - service.setName(service.getName() + "-changed"); - geoServer.save(service); - - get("/services/name/{name}", name) - .expectHeader() - .contentType(APPLICATION_JSON) - .expectStatus() - .isNoContent(); - } - - // GET /workspaces/{workspaceId}/services/name/{name} - @Test - void getServiceByWorkspaceAndName() { - addServicesToWorkspaceA(); - - testGetServiceByWorkspaceAndName(testData.wmsService); - testGetServiceByWorkspaceAndName(testData.wfsService); - testGetServiceByWorkspaceAndName(testData.wcsService); - testGetServiceByWorkspaceAndName(testData.wpsService); - } - - protected void addServicesToWorkspaceA() { - WorkspaceInfo ws = testData.workspaceA; - geoServer.getServices(ws).forEach(geoServer::remove); - - testData.wmsService.setWorkspace(ws); - testData.wcsService.setWorkspace(ws); - testData.wfsService.setWorkspace(ws); - testData.wpsService.setWorkspace(ws); - geoServer.add(testData.wmsService); - geoServer.add(testData.wcsService); - geoServer.add(testData.wfsService); - geoServer.add(testData.wpsService); - } - - private void testGetServiceByWorkspaceAndName(ServiceInfo service) { - WorkspaceInfo ws = testData.workspaceA; - - get("/workspaces/{workspaceId}/services/name/{name}", ws.getId(), service.getName()) - .expectStatus() - .isOk() - .expectHeader() - .contentType(APPLICATION_JSON) - .expectBody(ServiceInfo.class) - .value(s -> s.getId(), equalTo(service.getId())); - - String emptyWsId = testData.workspaceB.getId(); - get("/workspaces/{workspaceId}/services/name/{name}", emptyWsId, service.getName()) - .expectStatus() - .isNoContent() - .expectHeader() - .contentType(APPLICATION_JSON); - } - - private ResponseSpec put( - Object requestBody, String uri, Object... uriVariables) { - return testClient - .put() - .uri(toAbsoluteURI(uri), uriVariables) - .bodyValue(requestBody) - .accept(APPLICATION_JSON, APPLICATION_STREAM_JSON) - .exchange(); - } - - private ResponseSpec post( - Object requestBody, String uri, Object... uriVariables) { - return testClient - .post() - .uri(toAbsoluteURI(uri), uriVariables) - .bodyValue(requestBody) - .accept(APPLICATION_JSON, APPLICATION_STREAM_JSON) - .exchange(); - } - - private ResponseSpec patch( - Object requestBody, String uri, Object... uriVariables) { - return testClient - .patch() - .uri(toAbsoluteURI(uri), uriVariables) - .bodyValue(requestBody) - .accept(APPLICATION_JSON, APPLICATION_STREAM_JSON) - .exchange(); - } - - private ResponseSpec get(String uri, Object... uriVariables) { - return testClient - .get() - .uri(toAbsoluteURI(uri), uriVariables) - .accept(APPLICATION_JSON, APPLICATION_STREAM_JSON) - .exchange(); - } - - private ResponseSpec delete(String uri, Object... uriVariables) { - return testClient - .delete() - .uri(toAbsoluteURI(uri), uriVariables) - .accept(APPLICATION_JSON, APPLICATION_STREAM_JSON) - .exchange(); - } - - private String toAbsoluteURI(String relative) { - return baseURI + relative; - } -} diff --git a/src/catalog/catalog-server/server/src/test/java/org/geoserver/cloud/catalog/server/api/v1/ResourceInfoControllerTest.java b/src/catalog/catalog-server/server/src/test/java/org/geoserver/cloud/catalog/server/api/v1/ResourceInfoControllerTest.java deleted file mode 100644 index b15c0e35e..000000000 --- a/src/catalog/catalog-server/server/src/test/java/org/geoserver/cloud/catalog/server/api/v1/ResourceInfoControllerTest.java +++ /dev/null @@ -1,254 +0,0 @@ -/* - * (c) 2020 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.cloud.catalog.server.api.v1; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertFalse; - -import org.geoserver.catalog.CoverageInfo; -import org.geoserver.catalog.FeatureTypeInfo; -import org.geoserver.catalog.NamespaceInfo; -import org.geoserver.catalog.ResourceInfo; -import org.geoserver.catalog.WMSLayerInfo; -import org.geoserver.catalog.WMTSLayerInfo; -import org.geoserver.catalog.impl.ClassMappings; -import org.geoserver.catalog.impl.WMSLayerInfoImpl; -import org.geoserver.cloud.catalog.server.test.CatalogTestClient; -import org.geoserver.ows.util.OwsUtils; -import org.geotools.api.filter.Filter; -import org.junit.jupiter.api.Disabled; -import org.junit.jupiter.api.Test; -import org.springframework.boot.test.autoconfigure.web.reactive.AutoConfigureWebTestClient; -import org.springframework.http.MediaType; - -import java.io.IOException; -import java.util.List; - -@AutoConfigureWebTestClient(timeout = "360000") -class ResourceInfoControllerTest extends AbstractReactiveCatalogControllerTest { - - public ResourceInfoControllerTest() { - super(ResourceInfo.class); - } - - protected @Override void assertPropertriesEqual(ResourceInfo expected, ResourceInfo actual) { - assertEquals(expected.getAbstract(), actual.getAbstract()); - assertEquals(expected.getTitle(), actual.getTitle()); - assertEquals(expected.isEnabled(), actual.isEnabled()); - assertEquals(expected.isAdvertised(), actual.isAdvertised()); - assertEquals(expected.getDescription(), actual.getDescription()); - assertEquals(expected.getStore().getId(), actual.getStore().getId()); - } - - @Override - public @Test void testFindAll() { - super.testFindAll( - testData.featureTypeA, testData.coverageA, testData.wmsLayerA, testData.wmtsLayerA); - } - - @Override - public @Test void testFindById() { - super.testFindById(testData.featureTypeA); - super.testFindById(testData.coverageA); - super.testFindById(testData.wmsLayerA); - super.testFindById(testData.wmtsLayerA); - } - - @Override - public @Test void testFindAllByType() { - super.testFindAll( - ResourceInfo.class, - testData.featureTypeA, - testData.coverageA, - testData.wmsLayerA, - testData.wmtsLayerA); - super.testFindAll(FeatureTypeInfo.class, testData.featureTypeA); - super.testFindAll(CoverageInfo.class, testData.coverageA); - super.testFindAll(WMSLayerInfo.class, testData.wmsLayerA); - super.testFindAll(WMTSLayerInfo.class, testData.wmtsLayerA); - } - - @Override - public @Test void testQueryFilter() { - FeatureTypeInfo ft = - catalog.getResource(testData.featureTypeA.getId(), FeatureTypeInfo.class); - CoverageInfo cv = catalog.getResource(testData.coverageA.getId(), CoverageInfo.class); - WMSLayerInfo wms = catalog.getResource(testData.wmsLayerA.getId(), WMSLayerInfo.class); - WMTSLayerInfo wmts = catalog.getResource(testData.wmtsLayerA.getId(), WMTSLayerInfo.class); - - wms.setEnabled(false); - wmts.setEnabled(false); - cv.setEnabled(true); - catalog.save(wms); - catalog.save(wmts); - catalog.save(cv); - - super.testQueryFilter(ResourceInfo.class, Filter.INCLUDE, ft, cv, wms, wmts); - super.testQueryFilter(CoverageInfo.class, Filter.INCLUDE, cv); - super.testQueryFilter("enabled = true", ft, cv); - super.testQueryFilter("enabled = false", wms, wmts); - } - - @Test - void testResourceInfoCRUD_FeatureTypeInfo() { - FeatureTypeInfo toCreate = - testData.createFeatureType( - "featureTypeCRUD", - testData.dataStoreC, - testData.namespaceC, - "featureTypeCRUD_name", - "featureTypeCRUD abs", - "featureTypeCRUD desc", - true); - crudTest( - toCreate, - catalog::getFeatureType, - created -> { - created.setEnabled(!created.isEnabled()); - created.setName("modified ft name"); - created.setDescription("new description"); - }, - (orig, updated) -> { - assertFalse(updated.isEnabled()); - assertEquals("modified ft name", updated.getName()); - assertEquals("new description", updated.getDescription()); - }); - } - - @Test - void testResourceInfoCRUD_CoverageInfo() { - CoverageInfo toCreate = - testData.createCoverage( - "coverageCRUD", testData.coverageStoreA, "coverageCRUD_name"); - crudTest( - toCreate, - catalog::getCoverage, - created -> { - created.setEnabled(false); - created.setName("modified coverage name"); - created.setDescription("new description"); - }, - (orig, updated) -> { - assertFalse(updated.isEnabled()); - assertEquals("modified coverage name", updated.getName()); - assertEquals("new description", updated.getDescription()); - }); - } - - /** - * Horror here, ignored because {@link OwsUtils#copy} tries to connect to the real WMS service - * as calls {@link WMSLayerInfoImpl#getRemoteStyleInfos()} (fault is on WMSLayerInfo having a - * getter name for a method that does I/O). - * - *

{@code java.lang.IllegalAccessException: class - * org.geoserver.catalog.impl.ModificationProxyCloner cannot access a member of class - * java.util.Collections$EmptySet (in module java.base) with modifiers "private"} - */ - @Disabled - @Test - void testResourceInfoCRUD_WMSLayerInfo() { - WMSLayerInfo toCreate = - testData.createWMSLayer( - "wmsLayerCRUD", - testData.wmsStoreA, - testData.namespaceA, - "wmsLayerCRUD_name", - false); - crudTest( - toCreate, - id -> catalog.getResource(id, WMSLayerInfo.class), - created -> { - created.setEnabled(false); - created.setName("modified wms layer name"); - created.setDescription("new description"); - }, - (orig, updated) -> { - assertFalse(updated.isEnabled()); - assertEquals("modified wms layer name", updated.getName()); - assertEquals("new description", updated.getDescription()); - }); - } - - @Test - void testResourceInfoCRUD_WMTSLayerInfo() { - WMTSLayerInfo toCreate = - testData.createWMTSLayer( - "wmtsLayerCRUD", - testData.wmtsStoreA, - testData.namespaceA, - "wmtsLayerCRUD_name", - false); - crudTest( - toCreate, - id -> catalog.getResource(id, WMTSLayerInfo.class), - created -> { - created.setEnabled(false); - created.setName("modified wtms layer name"); - created.setDescription("new description"); - }, - (orig, updated) -> { - assertFalse(updated.isEnabled()); - assertEquals("modified wtms layer name", updated.getName()); - assertEquals("new description", updated.getDescription()); - }); - } - - @Test - void testFindResourceInfoById() { - testFindById(testData.featureTypeA); - testFindById(testData.coverageA); - testFindById(testData.wmsLayerA); - testFindById(testData.wmtsLayerA); - } - - @Test - void testFindResourceInfoById_SubtypeMismatch() throws IOException { - CatalogTestClient client = client(); - client.findById(testData.featureTypeA.getId(), CoverageInfo.class) - .expectStatus() - .isNoContent(); - client.findById(testData.coverageA.getId(), FeatureTypeInfo.class) - .expectStatus() - .isNoContent(); - client.findById(testData.wmsLayerA.getId(), WMTSLayerInfo.class) - .expectStatus() - .isNoContent(); - client.findById(testData.wmtsLayerA.getId(), WMSLayerInfo.class) - .expectStatus() - .isNoContent(); - } - - @Test - void testFindResourceByNamespaceIdAndName() { - NamespaceInfo ns = testData.namespaceA; - ResourceInfo ftA = testData.featureTypeA; - - client().getRelative( - "/namespaces/{namespaceId}/resources/name/{name}", - ns.getId(), - ftA.getName()) - .expectStatus() - .isOk() - .expectHeader() - .contentType(MediaType.APPLICATION_JSON) - .expectBody(FeatureTypeInfo.class) - .consumeWith(result -> assertEquals(ftA.getId(), result.getResponseBody().getId())); - } - - @Test - void testFindAllBySubtype() { - List all = super.findAll(ClassMappings.fromInterface(FeatureTypeInfo.class)); - assertEquals(catalog.getResources(FeatureTypeInfo.class).size(), all.size()); - - all = super.findAll(ClassMappings.fromInterface(CoverageInfo.class)); - assertEquals(catalog.getResources(CoverageInfo.class).size(), all.size()); - - all = super.findAll(ClassMappings.fromInterface(WMSLayerInfo.class)); - assertEquals(catalog.getResources(WMSLayerInfo.class).size(), all.size()); - - all = super.findAll(ClassMappings.fromInterface(WMTSLayerInfo.class)); - assertEquals(catalog.getResources(WMTSLayerInfo.class).size(), all.size()); - } -} diff --git a/src/catalog/catalog-server/server/src/test/java/org/geoserver/cloud/catalog/server/api/v1/StoreControllerTest.java b/src/catalog/catalog-server/server/src/test/java/org/geoserver/cloud/catalog/server/api/v1/StoreControllerTest.java deleted file mode 100644 index 46e628949..000000000 --- a/src/catalog/catalog-server/server/src/test/java/org/geoserver/cloud/catalog/server/api/v1/StoreControllerTest.java +++ /dev/null @@ -1,371 +0,0 @@ -/* - * (c) 2020 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.cloud.catalog.server.api.v1; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertFalse; - -import org.geoserver.catalog.CoverageStoreInfo; -import org.geoserver.catalog.DataStoreInfo; -import org.geoserver.catalog.HTTPStoreInfo; -import org.geoserver.catalog.NamespaceInfo; -import org.geoserver.catalog.StoreInfo; -import org.geoserver.catalog.WMSStoreInfo; -import org.geoserver.catalog.WMTSStoreInfo; -import org.geoserver.catalog.WorkspaceInfo; -import org.geoserver.catalog.impl.ClassMappings; -import org.geoserver.cloud.catalog.server.test.CatalogTestClient; -import org.geotools.api.filter.Filter; -import org.junit.jupiter.api.Test; -import org.springframework.boot.test.autoconfigure.web.reactive.AutoConfigureWebTestClient; -import org.springframework.http.MediaType; -import org.springframework.lang.Nullable; - -import java.io.IOException; -import java.io.Serializable; -import java.util.Arrays; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.stream.Collectors; - -@AutoConfigureWebTestClient(timeout = "360000") -class StoreControllerTest extends AbstractReactiveCatalogControllerTest { - - public StoreControllerTest() { - super(StoreInfo.class); - } - - protected @Override void assertPropertriesEqual(StoreInfo expected, StoreInfo actual) { - assertEquals(expected.getName(), actual.getName()); - assertEquals(expected.getDescription(), actual.getDescription()); - // connection params may have been serialized as string - final Map cm1 = - expected.getConnectionParameters() == null - ? new HashMap<>() - : expected.getConnectionParameters(); - final Map cm2 = - actual.getConnectionParameters() == null - ? new HashMap<>() - : actual.getConnectionParameters(); - assertEquals(cm1.size(), cm2.size()); - cm1.forEach((k, v) -> assertEquals(String.valueOf(v), String.valueOf(cm2.get(k)))); - assertEquals(expected.getType(), actual.getType()); - assertEquals(expected.getWorkspace(), actual.getWorkspace()); - assertEquals(expected.isEnabled(), actual.isEnabled()); - if (expected instanceof CoverageStoreInfo store) - assertEquals(store.getURL(), ((CoverageStoreInfo) actual).getURL()); - if (expected instanceof HTTPStoreInfo httpStore) - assertEquals( - httpStore.getCapabilitiesURL(), ((HTTPStoreInfo) actual).getCapabilitiesURL()); - } - - @Override - public @Test void testFindAll() { - super.testFindAll( - testData.dataStoreA, - testData.dataStoreB, - testData.dataStoreC, - testData.coverageStoreA, - testData.wmsStoreA, - testData.wmtsStoreA); - } - - @Override - public @Test void testFindById() { - super.testFindById(testData.dataStoreA); - super.testFindById(testData.coverageStoreA); - super.testFindById(testData.wmsStoreA); - super.testFindById(testData.wmtsStoreA); - } - - @Override - public @Test void testFindAllByType() { - super.testFindAll( - StoreInfo.class, - testData.dataStoreA, - testData.dataStoreB, - testData.dataStoreC, - testData.coverageStoreA, - testData.wmsStoreA, - testData.wmtsStoreA); - - super.testFindAll( - DataStoreInfo.class, testData.dataStoreA, testData.dataStoreB, testData.dataStoreC); - super.testFindAll(CoverageStoreInfo.class, testData.coverageStoreA); - super.testFindAll(WMSStoreInfo.class, testData.wmsStoreA); - super.testFindAll(WMTSStoreInfo.class, testData.wmtsStoreA); - } - - @Override - public @Test void testQueryFilter() { - DataStoreInfo ds1 = catalog.getDataStore(testData.dataStoreA.getId()); - DataStoreInfo ds2 = catalog.getDataStore(testData.dataStoreB.getId()); - DataStoreInfo ds3 = catalog.getDataStore(testData.dataStoreC.getId()); - CoverageStoreInfo cs1 = catalog.getCoverageStore(testData.coverageStoreA.getId()); - WMSStoreInfo wmss1 = catalog.getStore(testData.wmsStoreA.getId(), WMSStoreInfo.class); - WMTSStoreInfo wmtss1 = catalog.getStore(testData.wmtsStoreA.getId(), WMTSStoreInfo.class); - - super.testQueryFilter(StoreInfo.class, Filter.INCLUDE, ds1, ds2, ds3, cs1, wmss1, wmtss1); - super.testQueryFilter(StoreInfo.class, Filter.EXCLUDE); - super.testQueryFilter(DataStoreInfo.class, Filter.INCLUDE, ds1, ds2, ds3); - super.testQueryFilter(CoverageStoreInfo.class, Filter.INCLUDE, cs1); - super.testQueryFilter(WMSStoreInfo.class, Filter.INCLUDE, wmss1); - super.testQueryFilter(WMTSStoreInfo.class, Filter.INCLUDE, wmtss1); - - String ecql = String.format("\"workspace.name\" = '%s'", testData.workspaceA.getName()); - super.testQueryFilter(ecql, ds1, cs1, wmss1, wmtss1); - super.testQueryFilter(WMSStoreInfo.class, ecql, wmss1); - super.testQueryFilter(DataStoreInfo.class, ecql, ds1); - - ecql = String.format("\"workspace.id\" = '%s'", testData.workspaceB.getId()); - super.testQueryFilter(ecql, ds2); - } - - @Test - void testDataStoreInfo_CRUD() throws IOException { - DataStoreInfo store = - testData.faker() - .dataStoreInfo( - "dataStoreCRUD-id", - testData.workspaceB, - "dataStoreCRUD", - "dataStoreCRUD description", - true); - crudTest( - store, - catalog::getDataStore, - created -> { - created.setEnabled(false); - created.setName("modified name"); - created.setDescription("modified description"); - created.getConnectionParameters().put("newkey", "new param"); - return; - }, - (orig, updated) -> { - assertFalse(updated.isEnabled()); - assertEquals("modified name", updated.getName()); - assertEquals("modified description", updated.getDescription()); - assertEquals("new param", updated.getConnectionParameters().get("newkey")); - }); - } - - @Test - void testCoverageStoreInfo_CRUD() { - CoverageStoreInfo store = - testData.createCoverageStore( - "coverageStoreCRUD", - testData.workspaceC, - "coverageStoreCRUD name", - "GeoTIFF", - "file:/test/coverageStoreCRUD.tiff"); - crudTest( - store, - catalog::getCoverageStore, - created -> { - created.setEnabled(false); - created.setName("modified name"); - created.setDescription("modified description"); - ((CoverageStoreInfo) created) - .setURL("file:/test/coverageStoreCRUD_modified.tiff"); - return; - }, - (orig, updated) -> { - assertFalse(updated.isEnabled()); - assertEquals("modified name", updated.getName()); - assertEquals("modified description", updated.getDescription()); - assertEquals( - "file:/test/coverageStoreCRUD_modified.tiff", - ((CoverageStoreInfo) updated).getURL()); - }); - } - - @Test - void testWMSStoreInfo_CRUD() { - WMSStoreInfo store = - testData.createWebMapServer( - "wmsStoreCRUD", - testData.workspaceA, - "wmsStoreCRUD_name", - "http://test.com", - true); - crudTest( - store, - id -> catalog.getStore(id, WMSStoreInfo.class), - created -> { - created.setEnabled(false); - created.setName("modified name"); - created.setDescription("modified description"); - ((WMSStoreInfo) created).setCapabilitiesURL("http://new.caps.url"); - return; - }, - (orig, updated) -> { - assertFalse(updated.isEnabled()); - assertEquals("modified name", updated.getName()); - assertEquals("modified description", updated.getDescription()); - assertEquals( - "http://new.caps.url", ((WMSStoreInfo) updated).getCapabilitiesURL()); - }); - } - - @Test - void testWMTSStoreInfo_CRUD() { - WMTSStoreInfo store = - testData.createWebMapTileServer( - "wmsStoreCRUD", - testData.workspaceA, - "wmtsStoreCRUD_name", - "http://test.com", - true); - crudTest( - store, - id -> catalog.getStore(id, WMTSStoreInfo.class), - created -> { - created.setEnabled(false); - created.setName("modified name"); - created.setDescription("modified description"); - ((WMTSStoreInfo) created).setCapabilitiesURL("http://new.caps.url"); - return; - }, - (orig, updated) -> { - assertFalse(updated.isEnabled()); - assertEquals("modified name", updated.getName()); - assertEquals("modified description", updated.getDescription()); - assertEquals( - "http://new.caps.url", ((WMTSStoreInfo) updated).getCapabilitiesURL()); - }); - } - - @Test - void testFindStoreById() throws IOException { - testFindById(testData.coverageStoreA); - testFindById(testData.dataStoreA); - testFindById(testData.dataStoreB); - testFindById(testData.wmsStoreA); - testFindById(testData.wmtsStoreA); - } - - @Test - void testFindStoreById_SubtypeMismatch() throws IOException { - CatalogTestClient client = client(); - client.findById(testData.coverageStoreA.getId(), DataStoreInfo.class) - .expectStatus() - .isNoContent(); - client.findById(testData.dataStoreA.getId(), CoverageStoreInfo.class) - .expectStatus() - .isNoContent(); - client.findById(testData.dataStoreB.getId(), CoverageStoreInfo.class) - .expectStatus() - .isNoContent(); - } - - @Test - void testFindStoreByName() throws IOException { - findStoreByName(testData.coverageStoreA); - findStoreByName(testData.dataStoreA); - findStoreByName(testData.dataStoreB); - findStoreByName(testData.wmsStoreA); - findStoreByName(testData.wmtsStoreA); - } - - private void findStoreByName(StoreInfo store) { - StoreInfo responseBody = client().getFirstByName(store.getName()); - StoreInfo resolved = resolveProxies(responseBody); - assertCatalogInfoEquals(store, resolved); - } - - @Test - void testFindStoreByWorkspaceAndName() throws IOException { - testFindStoreByWorkspaceAndName(testData.coverageStoreA, null); - testFindStoreByWorkspaceAndName(testData.coverageStoreA, ClassMappings.COVERAGESTORE); - - testFindStoreByWorkspaceAndName(testData.dataStoreA, null); - testFindStoreByWorkspaceAndName(testData.dataStoreA, ClassMappings.DATASTORE); - - testFindStoreByWorkspaceAndName(testData.dataStoreB, null); - testFindStoreByWorkspaceAndName(testData.dataStoreB, ClassMappings.DATASTORE); - - testFindStoreByWorkspaceAndName(testData.wmsStoreA, null); - testFindStoreByWorkspaceAndName(testData.wmsStoreA, ClassMappings.WMSSTORE); - - testFindStoreByWorkspaceAndName(testData.wmtsStoreA, null); - testFindStoreByWorkspaceAndName(testData.wmtsStoreA, ClassMappings.WMTSSTORE); - } - - private void testFindStoreByWorkspaceAndName(StoreInfo store, @Nullable ClassMappings subType) { - String workspaceId = store.getWorkspace().getId(); - String name = store.getName(); - - StoreInfo found = - client().getRelative( - "/workspaces/{workspaceId}/stores/name/{name}?type={subType}", - workspaceId, - name, - subType) - .expectStatus() - .isOk() - .expectBody(StoreInfo.class) - .returnResult() - .getResponseBody(); - assertEquals(store.getId(), found.getId()); - assertEquals(store.getName(), found.getName()); - } - - @Test - void testFindStoreByName_WrongWorkspace() throws IOException { - testFindStoreByName_WrongWorkspace(testData.coverageStoreA, testData.workspaceC); - testFindStoreByName_WrongWorkspace(testData.dataStoreA, testData.workspaceC); - testFindStoreByName_WrongWorkspace(testData.dataStoreB, testData.workspaceC); - testFindStoreByName_WrongWorkspace(testData.wmsStoreA, testData.workspaceC); - testFindStoreByName_WrongWorkspace(testData.wmtsStoreA, testData.workspaceC); - } - - private void testFindStoreByName_WrongWorkspace(StoreInfo store, WorkspaceInfo workspace) { - String name = store.getName(); - ClassMappings subType = null; - client().getRelative( - "/workspaces/{workspaceId}/stores/name/{name}?type={subType}", - workspace.getId(), - name, - subType) - .expectStatus() - .isNoContent(); - } - - @Test - void testFindStoresByWorkspace() { - testFindStoresByWorkspace( - testData.workspaceA, - testData.dataStoreA, - testData.coverageStoreA, - testData.wmsStoreA, - testData.wmtsStoreA); - testFindStoresByWorkspace(testData.workspaceB, testData.dataStoreB); - WorkspaceInfo emptyWs = testData.faker().workspaceInfo("emptyws"); - NamespaceInfo emptyNs = testData.faker().namespace(); - catalog.add(emptyWs); - catalog.add(emptyNs); - testFindStoresByWorkspace(emptyWs); - } - - public void testFindStoresByWorkspace(WorkspaceInfo ws, StoreInfo... expected) { - List stores = - client().getRelative("/workspaces/{workspaceId}/stores", ws.getId()) - .expectStatus() - .isOk() - .expectHeader() - .contentType(MediaType.APPLICATION_STREAM_JSON) - .expectBodyList(StoreInfo.class) - .returnResult() - .getResponseBody(); - - Set expectedIds = - Arrays.stream(expected).map(StoreInfo::getId).collect(Collectors.toSet()); - Set actual = stores.stream().map(StoreInfo::getId).collect(Collectors.toSet()); - - assertEquals(expectedIds, actual); - } -} diff --git a/src/catalog/catalog-server/server/src/test/java/org/geoserver/cloud/catalog/server/api/v1/StyleControllerTest.java b/src/catalog/catalog-server/server/src/test/java/org/geoserver/cloud/catalog/server/api/v1/StyleControllerTest.java deleted file mode 100644 index 9d472ee51..000000000 --- a/src/catalog/catalog-server/server/src/test/java/org/geoserver/cloud/catalog/server/api/v1/StyleControllerTest.java +++ /dev/null @@ -1,278 +0,0 @@ -/* - * (c) 2020 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.cloud.catalog.server.api.v1; - -import static org.junit.jupiter.api.Assertions.assertEquals; - -import org.geoserver.catalog.LegendInfo; -import org.geoserver.catalog.SLDHandler; -import org.geoserver.catalog.StyleInfo; -import org.geoserver.catalog.WorkspaceInfo; -import org.geoserver.catalog.impl.LegendInfoImpl; -import org.geoserver.catalog.impl.StyleInfoImpl; -import org.geotools.api.filter.Filter; -import org.junit.jupiter.api.Test; -import org.springframework.boot.test.autoconfigure.web.reactive.AutoConfigureWebTestClient; -import org.springframework.http.MediaType; - -import java.util.Arrays; -import java.util.List; -import java.util.Set; -import java.util.stream.Collectors; - -@AutoConfigureWebTestClient(timeout = "360000") -class StyleControllerTest extends AbstractReactiveCatalogControllerTest { - - public StyleControllerTest() { - super(StyleInfo.class); - } - - protected @Override void assertPropertriesEqual(StyleInfo expected, StyleInfo actual) { - assertEquals(expected.getName(), actual.getName()); - assertEquals(expected.getFilename(), actual.getFilename()); - assertEquals(expected.getFormat(), actual.getFormat()); - assertEquals(expected.getFormatVersion(), actual.getFormatVersion()); - assertEquals(expected.getWorkspace(), actual.getWorkspace()); - assertLegendEquals(expected.getLegend(), actual.getLegend()); - } - - private void assertLegendEquals(LegendInfo expected, LegendInfo actual) { - if (expected == null || actual == null) assertEquals(expected, actual); - else { - assertEquals(expected.getFormat(), actual.getFormat()); - assertEquals(expected.getHeight(), actual.getHeight()); - assertEquals(expected.getOnlineResource(), actual.getOnlineResource()); - assertEquals(expected.getWidth(), actual.getWidth()); - } - } - - @Test - void testStyleCRUD_NoWorkspace() { - StyleInfo style = testData.createStyle("styleCRUD", null, "styleCRUD", "styleCRUD.sld"); - ((StyleInfoImpl) style).setFormat(SLDHandler.FORMAT); - ((StyleInfoImpl) style).setFormatVersion(SLDHandler.VERSION_10); - crudTest( - style, - catalog::getStyle, - created -> { - created.setName(created.getName() + "_modified"); - // this will be assigned by the catalog as the new file name when it renames the - // style, - // so change it here too for the equals check to pass - created.setFilename(created.getName() + ".sld"); - created.setFormat(SLDHandler.FORMAT); - created.setFormatVersion(SLDHandler.VERSION_11); - LegendInfoImpl legend = new LegendInfoImpl(); - legend.setFormat("test"); - legend.setHeight(10); - legend.setWidth(20); - legend.setOnlineResource("http://test.com/style.png"); - created.setLegend(legend); - }, - (orig, updated) -> { - assertEquals(orig.getName() + "_modified", updated.getName()); - assertEquals(updated.getName() + ".sld", updated.getFilename()); - assertEquals(SLDHandler.FORMAT, updated.getFormat()); - assertEquals(SLDHandler.VERSION_11, updated.getFormatVersion()); - assertEquals("test", updated.getLegend().getFormat()); - assertEquals(10, updated.getLegend().getHeight()); - assertEquals(20, updated.getLegend().getWidth()); - assertEquals( - "http://test.com/style.png", updated.getLegend().getOnlineResource()); - }); - } - - @Test - void testStyleCRUD_Workspace() { - StyleInfo style = - testData.createStyle( - "styleCRUD_Workspace", - testData.workspaceB, - "styleCRUD_Workspace", - "styleCRUD_Workspace.sld"); - - style.setFormat(SLDHandler.FORMAT); - style.setFormatVersion(SLDHandler.VERSION_10); - - crudTest( - style, - catalog::getStyle, - created -> { - created.setWorkspace(testData.workspaceC); - created.setFormatVersion(SLDHandler.VERSION_11); - }, - (orig, updated) -> { - assertEquals(testData.workspaceC, updated.getWorkspace()); - assertEquals(SLDHandler.VERSION_11, updated.getFormatVersion()); - }); - } - - public @Test @Override void testFindById() { - testFindById(testData.style1); - testFindById(testData.style2); - } - - public @Test @Override void testFindAll() { - testFindAll(testData.style1, testData.style2); - - WorkspaceInfo ws1 = testData.workspaceA; - WorkspaceInfo ws2 = testData.workspaceB; - StyleInfo ws1s1 = testData.createStyle("s1ws1", ws1); - StyleInfo ws2s1 = testData.createStyle("s1ws2", ws2); - catalog.add(ws1s1); - catalog.add(ws2s1); - - testFindAll(testData.style1, testData.style2, ws1s1, ws2s1); - } - - public @Test @Override void testFindAllByType() { - testFindAll(StyleInfo.class, testData.style1, testData.style2); - } - - public @Test @Override void testQueryFilter() { - WorkspaceInfo ws1 = testData.workspaceA; - WorkspaceInfo ws2 = testData.workspaceB; - - StyleInfo ws1s1 = testData.createStyle("s1ws1", ws1); - StyleInfo ws1s2 = testData.createStyle("s2ws1", ws1); - StyleInfo ws2s1 = testData.createStyle("s1ws2", ws2); - StyleInfo ws2s2 = testData.createStyle("s2ws2", ws2); - catalog.add(ws1s1); - catalog.add(ws1s2); - catalog.add(ws2s1); - catalog.add(ws2s2); - - super.testQueryFilter( - StyleInfo.class, - Filter.INCLUDE, - testData.style1, - testData.style2, - ws1s1, - ws1s2, - ws2s1, - ws2s2); - String cql = "name like '%ws1'"; - super.testQueryFilter(cql, ws1s1, ws1s2); - } - - @Test - void testFindStyleByNameAndNullWorkspace() { - WorkspaceInfo ws1 = testData.workspaceA; - StyleInfo ws1s1 = testData.createStyle("s1ws1", ws1); - catalog.add(ws1s1); - - testFindStyleByNameAndNullWorkspace(testData.style1); - testFindStyleByNameAndNullWorkspace(testData.style2); - - client().getRelative("/styles/noworkspace/{name}", ws1s1.getName()) - .expectStatus() - .isNoContent(); - } - - private void testFindStyleByNameAndNullWorkspace(StyleInfo style) { - client().getRelative("/styles/noworkspace/{name}", style.getName()) - .expectStatus() - .isOk() - .expectHeader() - .contentType(MediaType.APPLICATION_JSON) - .expectBody(StyleInfo.class) - .consumeWith(r -> assertEquals(style.getId(), r.getResponseBody().getId())); - } - - @Test - void testfindStyleByWorkspaceIdAndName() { - WorkspaceInfo ws1 = testData.workspaceA; - WorkspaceInfo ws2 = testData.workspaceB; - StyleInfo ws1s1 = testData.createStyle("s1ws1", ws1); - StyleInfo ws2s1 = testData.createStyle("s1ws2", ws2); - catalog.add(ws1s1); - catalog.add(ws2s1); - - testfindStyleByWorkspaceIdAndName(ws1, ws1s1); - testfindStyleByWorkspaceIdAndName(ws2, ws2s1); - - client().getRelative( - "/workspaces/{workspaceId}/styles/{name}", ws1.getId(), ws2s1.getName()) - .expectStatus() - .isNoContent(); - } - - private void testfindStyleByWorkspaceIdAndName(WorkspaceInfo ws, StyleInfo style) { - client().getRelative("/workspaces/{workspaceId}/styles/{name}", ws.getId(), style.getName()) - .expectStatus() - .isOk() - .expectHeader() - .contentType(MediaType.APPLICATION_JSON) - .expectBody(StyleInfo.class) - .consumeWith(r -> assertEquals(style.getId(), r.getResponseBody().getId())); - } - - @Test - void testFindStylesByNullWorkspace() { - StyleInfo ws1s1 = testData.createStyle("s1ws1", testData.workspaceA); - catalog.add(ws1s1); - - List expected = Arrays.asList(testData.style1, testData.style2); - - client().getRelative("/styles/noworkspace") - .expectStatus() - .isOk() - .expectHeader() - .contentType(MediaType.APPLICATION_STREAM_JSON) - .expectBodyList(StyleInfo.class) - .consumeWith( - response -> { - Set expectedIds = - expected.stream() - .map(StyleInfo::getId) - .collect(Collectors.toSet()); - Set returnedIds = - response.getResponseBody().stream() - .map(StyleInfo::getId) - .collect(Collectors.toSet()); - assertEquals(expectedIds, returnedIds); - }); - } - - @Test - void testFindStylesByWorkspaceId() { - WorkspaceInfo ws1 = testData.workspaceA; - WorkspaceInfo ws2 = testData.workspaceB; - - StyleInfo ws1s1 = testData.createStyle("s1ws1", ws1); - StyleInfo ws1s2 = testData.createStyle("s2ws1", ws1); - StyleInfo ws2s1 = testData.createStyle("s1ws2", ws2); - StyleInfo ws2s2 = testData.createStyle("s2ws2", ws2); - catalog.add(ws1s1); - catalog.add(ws1s2); - catalog.add(ws2s1); - catalog.add(ws2s2); - - testFindStylesByWorkspaceId(ws1, ws1s1, ws1s2); - testFindStylesByWorkspaceId(ws2, ws2s1, ws2s2); - testFindStylesByWorkspaceId(testData.workspaceC); - } - - private void testFindStylesByWorkspaceId(WorkspaceInfo ws1, StyleInfo... expected) { - client().getRelative("/workspaces/{workspaceId}/styles", ws1.getId()) - .expectStatus() - .isOk() - .expectHeader() - .contentType(MediaType.APPLICATION_STREAM_JSON) - .expectBodyList(StyleInfo.class) - .consumeWith( - response -> { - Set expectedIds = - Arrays.stream(expected) - .map(StyleInfo::getId) - .collect(Collectors.toSet()); - Set returnedIds = - response.getResponseBody().stream() - .map(StyleInfo::getId) - .collect(Collectors.toSet()); - assertEquals(expectedIds, returnedIds); - }); - } -} diff --git a/src/catalog/catalog-server/server/src/test/java/org/geoserver/cloud/catalog/server/api/v1/WorkspaceControllerTest.java b/src/catalog/catalog-server/server/src/test/java/org/geoserver/cloud/catalog/server/api/v1/WorkspaceControllerTest.java deleted file mode 100644 index 193072ff8..000000000 --- a/src/catalog/catalog-server/server/src/test/java/org/geoserver/cloud/catalog/server/api/v1/WorkspaceControllerTest.java +++ /dev/null @@ -1,134 +0,0 @@ -/* - * (c) 2020 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.cloud.catalog.server.api.v1; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertNotNull; -import static org.junit.jupiter.api.Assertions.assertNull; -import static org.junit.jupiter.api.Assertions.assertTrue; - -import static java.lang.String.format; - -import org.geoserver.catalog.WorkspaceInfo; -import org.junit.jupiter.api.Test; -import org.springframework.boot.test.autoconfigure.web.reactive.AutoConfigureWebTestClient; -import org.springframework.http.MediaType; - -@AutoConfigureWebTestClient(timeout = "360000") -class WorkspaceControllerTest extends AbstractReactiveCatalogControllerTest { - - public WorkspaceControllerTest() { - super(WorkspaceInfo.class); - } - - protected @Override void assertPropertriesEqual(WorkspaceInfo expected, WorkspaceInfo actual) { - assertEquals(expected.getName(), actual.getName()); - assertEquals(expected.isIsolated(), actual.isIsolated()); - } - - @Override - public @Test void testFindById() { - testFindById(testData.workspaceA); - testFindById(testData.workspaceB); - testFindById(testData.workspaceC); - } - - @Override - public @Test void testFindAll() { - super.testFindAll(testData.workspaceA, testData.workspaceB, testData.workspaceC); - } - - @Override - public @Test void testFindAllByType() { - super.testFindAll( - WorkspaceInfo.class, testData.workspaceA, testData.workspaceB, testData.workspaceC); - } - - @Test - void testFindByName() { - WorkspaceInfo ws1 = testData.workspaceA; - assertEquals(ws1, client().getFirstByName(ws1.getName())); - } - - @Override - public @Test void testQueryFilter() { - WorkspaceInfo wsA = catalog.getWorkspace(testData.workspaceA.getId()); - WorkspaceInfo wsB = catalog.getWorkspace(testData.workspaceB.getId()); - WorkspaceInfo wsC = catalog.getWorkspace(testData.workspaceC.getId()); - - wsB.setIsolated(true); - wsC.setIsolated(true); - catalog.save(wsB); - catalog.save(wsC); - - super.testQueryFilter("isolated = true", wsB, wsC); - super.testQueryFilter("isolated = false", wsA); - super.testQueryFilter(format("\"id\" = '%s'", wsA.getId()), wsA); - } - - @Test - void testWorkspaceCRUD() { - WorkspaceInfo ws = testData.faker().workspaceInfo("workspaceCRUD"); - crudTest( - ws, - catalog::getWorkspace, - w -> { - w.setName("modified_name"); - w.setIsolated(true); - }, - (orig, updated) -> { - assertEquals("modified_name", updated.getName()); - assertTrue(updated.isIsolated()); - }); - } - - @Test - void testGetDefaultWorkspace() { - WorkspaceInfo expected = catalog.getDefaultWorkspace(); - assertNotNull(expected); - WorkspaceInfo actual = - client().getRelative("/workspaces/default") - .expectStatus() - .isOk() - .expectHeader() - .contentType(MediaType.APPLICATION_JSON) - .expectBody(WorkspaceInfo.class) - .returnResult() - .getResponseBody(); - assertEquals(expected, actual); - } - - @Test - void testGetDefaultWorkspaceIsNullOnEmptyCatalog() { - testData.deleteAll(); - assertNull(catalog.getDefaultWorkspace()); - - client().getRelative("/workspaces/default") - .expectStatus() - .isNoContent() - .expectHeader() - .contentType(MediaType.APPLICATION_JSON); - } - - @Test - void testSetDefaultWorkspace() { - WorkspaceInfo current = catalog.getDefaultWorkspace(); - assertNotNull(current); - assertEquals(testData.workspaceA.getId(), current.getId()); - - WorkspaceInfo expected = catalog.getWorkspace(testData.workspaceB.getId()); - - WorkspaceInfo actual = - client().put("/workspaces/default/{id}", expected.getId()) - .expectStatus() - .isOk() - .expectHeader() - .contentType(MediaType.APPLICATION_JSON) - .expectBody(WorkspaceInfo.class) - .returnResult() - .getResponseBody(); - assertEquals(expected, actual); - } -} diff --git a/src/catalog/catalog-server/server/src/test/java/org/geoserver/cloud/catalog/server/test/CatalogTestClient.java b/src/catalog/catalog-server/server/src/test/java/org/geoserver/cloud/catalog/server/test/CatalogTestClient.java deleted file mode 100644 index 62b3db4b0..000000000 --- a/src/catalog/catalog-server/server/src/test/java/org/geoserver/cloud/catalog/server/test/CatalogTestClient.java +++ /dev/null @@ -1,178 +0,0 @@ -/* - * (c) 2020 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.cloud.catalog.server.test; - -import static org.springframework.http.MediaType.APPLICATION_JSON; - -import lombok.NonNull; -import lombok.RequiredArgsConstructor; - -import org.geoserver.catalog.CatalogInfo; -import org.geoserver.catalog.impl.ClassMappings; -import org.geoserver.catalog.impl.ModificationProxy; -import org.geoserver.catalog.plugin.Patch; -import org.geoserver.catalog.plugin.PropertyDiff; -import org.springframework.http.MediaType; -import org.springframework.test.web.reactive.server.WebTestClient; -import org.springframework.test.web.reactive.server.WebTestClient.RequestBodySpec; -import org.springframework.test.web.reactive.server.WebTestClient.ResponseSpec; - -import java.lang.reflect.Proxy; -import java.util.function.Consumer; - -import javax.annotation.Nullable; - -@RequiredArgsConstructor -public class CatalogTestClient { - - private final @NonNull WebTestClient client; - - protected final @NonNull Class infoType; - - protected final @NonNull String baseUri; - - public ResponseSpec create(C info) { - return doPost(info, "/{endpoint}", endpoint()); - } - - /** Calls update with {@link Patch} on the server, does not modify {@code info} */ - public ResponseSpec update(C info, Consumer modifyingConsumer) { - C real = ModificationProxy.unwrap(info); - Class clazz = real.getClass(); - ClassMappings classMappings = ClassMappings.fromImpl(clazz); - @SuppressWarnings("unchecked") - C proxied = (C) ModificationProxy.create(info, classMappings.getInterface()); - - modifyingConsumer.accept(proxied); - ModificationProxy proxy = (ModificationProxy) Proxy.getInvocationHandler(proxied); - Patch patch = PropertyDiff.valueOf(proxy).toPatch(); - - return patchAbsoluteURI(patch, baseUri + "/{endpoint}/{id}", endpoint(), info.getId()); - } - - public ResponseSpec delete(C info) { - return doDelete(info, baseUri + "/{endpoint}/{id}", endpoint(), info.getId()); - } - - public ResponseSpec findById(@NonNull C expected) { - @SuppressWarnings("unchecked") - Class type = - (Class) ClassMappings.fromImpl(expected.getClass()).getInterface(); - return findById(expected.getId(), type); - } - - public ResponseSpec findById(String id) { - return findById(id, infoType); - } - - /** - * Calls {@link #findById(String, ClassMappings)} on the controller under test and for the - * requested subtype, if provided. - */ - public ResponseSpec findById(String id, @NonNull Class requestedType) { - String endpoint = endpoint(); - String uri = baseUri + "/{endpoint}/{id}?type={subtype}"; - ClassMappings subType = null; - if (!infoType.equals(requestedType)) { - subType = ClassMappings.fromInterface(requestedType); - } - return getWithAbsolutePath(uri, endpoint, id, subType); - } - - private String endpoint() { - String endpoint = ClassMappings.fromInterface(infoType).toString().toLowerCase() + "s"; - return endpoint; - } - - public C getFirstByName(String name) { - return findFirstByName(name, infoType) - .expectStatus() - .isOk() - .expectBody(infoType) - .returnResult() - .getResponseBody(); - } - - public ResponseSpec findFirstByName( // - String localName, // - @NonNull Class requestedType) { - - String uri = baseUri + "/{endpoint}/name/{name}/first?type={type}"; - ClassMappings subType = ClassMappings.fromInterface(requestedType); - return getWithAbsolutePath(uri, endpoint(), localName, subType); - } - - public ResponseSpec getRelative(String uri, Object... uriVariables) { - uri = baseUri + uri; - return client.get() - .uri(uri, uriVariables) - .accept(MediaType.APPLICATION_JSON, MediaType.APPLICATION_STREAM_JSON) - .exchange(); - } - - public ResponseSpec getWithAbsolutePath( - String uri, Object... uriVariables) { - return client.get().uri(uri, uriVariables).exchange(); - } - - public ResponseSpec doPost( - @NonNull Object requestBody, // - @NonNull String uri, - Object... uriVariables) { - - uri = baseUri + uri; - return client.post() - .uri(uri, uriVariables) - .contentType(APPLICATION_JSON) - .bodyValue(requestBody) - .exchange(); - } - - public ResponseSpec put(@NonNull String uri, Object... uriVariables) { - return putAbsoluteURI(null, baseUri + uri, uriVariables); - } - - public ResponseSpec putWithBody( - @NonNull Object requestBody, @NonNull String uri, Object... uriVariables) { - return putAbsoluteURI(requestBody, baseUri + uri, uriVariables); - } - - public ResponseSpec patchWithBody( - @NonNull Object requestBody, @NonNull String uri, Object... uriVariables) { - return patchAbsoluteURI(requestBody, baseUri + uri, uriVariables); - } - - public ResponseSpec putAbsoluteURI( - @Nullable Object requestBody, // - @NonNull String uri, - Object... uriVariables) { - - RequestBodySpec bodySpec = - client.put().uri(uri, uriVariables).contentType(APPLICATION_JSON); - if (requestBody != null) return bodySpec.bodyValue(requestBody).exchange(); - - return bodySpec.exchange(); - } - - public ResponseSpec patchAbsoluteURI( - @Nullable Object requestBody, // - @NonNull String uri, - Object... uriVariables) { - - RequestBodySpec bodySpec = - client.patch().uri(uri, uriVariables).contentType(APPLICATION_JSON); - if (requestBody != null) return bodySpec.bodyValue(requestBody).exchange(); - - return bodySpec.exchange(); - } - - public ResponseSpec doDelete( - @NonNull Object requestBody, // - @NonNull String uri, - Object... uriVariables) { - - return client.delete().uri(uri, uriVariables).accept(APPLICATION_JSON).exchange(); - } -} diff --git a/src/catalog/catalog-server/server/src/test/java/org/geoserver/cloud/catalog/server/test/TestConfiguration.java b/src/catalog/catalog-server/server/src/test/java/org/geoserver/cloud/catalog/server/test/TestConfiguration.java deleted file mode 100644 index 5f7f530ec..000000000 --- a/src/catalog/catalog-server/server/src/test/java/org/geoserver/cloud/catalog/server/test/TestConfiguration.java +++ /dev/null @@ -1,20 +0,0 @@ -/* - * (c) 2020 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.cloud.catalog.server.test; - -import org.springframework.boot.actuate.autoconfigure.security.reactive.ReactiveManagementWebSecurityAutoConfiguration; -import org.springframework.boot.autoconfigure.EnableAutoConfiguration; -import org.springframework.boot.autoconfigure.security.reactive.ReactiveSecurityAutoConfiguration; -import org.springframework.boot.autoconfigure.security.reactive.ReactiveUserDetailsServiceAutoConfiguration; -import org.springframework.context.annotation.Configuration; - -@Configuration -@EnableAutoConfiguration( - exclude = { // - ReactiveSecurityAutoConfiguration.class, // - ReactiveUserDetailsServiceAutoConfiguration.class, // - ReactiveManagementWebSecurityAutoConfiguration.class // - }) -public class TestConfiguration {} diff --git a/src/catalog/catalog-server/server/src/test/java/org/geoserver/cloud/catalog/server/test/WebTestClientSupport.java b/src/catalog/catalog-server/server/src/test/java/org/geoserver/cloud/catalog/server/test/WebTestClientSupport.java deleted file mode 100644 index b126e73b4..000000000 --- a/src/catalog/catalog-server/server/src/test/java/org/geoserver/cloud/catalog/server/test/WebTestClientSupport.java +++ /dev/null @@ -1,80 +0,0 @@ -/* - * (c) 2020 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.cloud.catalog.server.test; - -import lombok.NonNull; - -import org.geoserver.catalog.CatalogInfo; -import org.geoserver.catalog.LayerGroupInfo; -import org.geoserver.catalog.LayerInfo; -import org.geoserver.catalog.NamespaceInfo; -import org.geoserver.catalog.ResourceInfo; -import org.geoserver.catalog.StoreInfo; -import org.geoserver.catalog.StyleInfo; -import org.geoserver.catalog.WorkspaceInfo; -import org.geoserver.cloud.catalog.server.api.v1.ReactiveCatalogController; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.test.web.reactive.server.WebTestClient; - -import java.util.function.Supplier; - -import javax.annotation.PostConstruct; - -/** - * Configures the {@link WebTestClient} to be able of encoding and decoding {@link CatalogInfo} - * objects - */ -public class WebTestClientSupport implements Supplier { - - protected @Autowired WebTestClient client; - - protected @PostConstruct void setup() { - // client = - // client.mutate() - // .codecs( - // configurer -> { - // configurer.customCodecs().registerWithDefaultConfig(encoder); - // configurer.customCodecs().registerWithDefaultConfig(decoder); - // }) - // .build(); - } - - @Override - public WebTestClient get() { - return client; - } - - public CatalogTestClient clientFor(@NonNull Class infoType) { - return new CatalogTestClient(client, infoType, ReactiveCatalogController.BASE_URI); - } - - public CatalogTestClient workspaces() { - return clientFor(WorkspaceInfo.class); - } - - public CatalogTestClient namespaces() { - return clientFor(NamespaceInfo.class); - } - - public CatalogTestClient stores() { - return clientFor(StoreInfo.class); - } - - public CatalogTestClient resources() { - return clientFor(ResourceInfo.class); - } - - public CatalogTestClient layers() { - return clientFor(LayerInfo.class); - } - - public CatalogTestClient layerGroups() { - return clientFor(LayerGroupInfo.class); - } - - public CatalogTestClient styles() { - return clientFor(StyleInfo.class); - } -} diff --git a/src/catalog/catalog-server/server/src/test/java/org/geoserver/cloud/catalog/server/test/WebTestClientSupportConfiguration.java b/src/catalog/catalog-server/server/src/test/java/org/geoserver/cloud/catalog/server/test/WebTestClientSupportConfiguration.java deleted file mode 100644 index 9e7e3ce53..000000000 --- a/src/catalog/catalog-server/server/src/test/java/org/geoserver/cloud/catalog/server/test/WebTestClientSupportConfiguration.java +++ /dev/null @@ -1,23 +0,0 @@ -/* - * (c) 2020 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.cloud.catalog.server.test; - -import org.geoserver.catalog.CatalogInfo; -import org.springframework.boot.test.autoconfigure.web.reactive.AutoConfigureWebTestClient; -import org.springframework.context.annotation.Bean; -import org.springframework.test.web.reactive.server.WebTestClient; - -/** - * Configures the {@link WebTestClient} to be able of encoding and decoding {@link CatalogInfo} - * objects using {@link CatalogInfoXmlEncoder} and {@link CatalogInfoXmlDecoder} - */ -@AutoConfigureWebTestClient(timeout = "360000") -public class WebTestClientSupportConfiguration { - - @Bean - WebTestClientSupport webTestClientSupport() { - return new WebTestClientSupport(); - } -} diff --git a/src/catalog/catalog-server/server/src/test/resources/application-test.yml b/src/catalog/catalog-server/server/src/test/resources/application-test.yml deleted file mode 100644 index 904e663bf..000000000 --- a/src/catalog/catalog-server/server/src/test/resources/application-test.yml +++ /dev/null @@ -1,45 +0,0 @@ -server.error.includeStacktrace: always - -spring: - jackson.serialization.indent_output: true - main: - banner-mode: off - allow-bean-definition-overriding: true - allow-circular-references: true # false by default since spring-boot 2.6.0, breaks geoserver initialization - cloud.config.enabled: false - cloud.config.discovery.enabled: false - cloud.bus.enabled: false -eureka.client.enabled: false -hystrix.command.default.execution.timeout.enabled: false -hystrix.command.default.execution.isolation.thread.timeoutInMilliseconds: 50000 - -geoserver: - catalog: - secure: false - advertised: false - backend: - data-directory: - enabled: true - location: ${data_directory:${java.io.tmpdir}/geoserver_cloud_data_directory} - jdbcconfig: - enabled: false - web.enabled: false - initdb: true - cache-directory: ${java.io.tmpdir}/geoserver-jdbcconfig-cache - datasource: - driverClassname: org.h2.Driver - url: jdbc:h2:mem:test;DB_CLOSE_DELAY=-1 - username: sa - password: - -logging: - level: - root: WARN - org.geoserver.platform: ERROR - org.geoserver.jackson: DEBUG - org.geotools.jackson: DEBUG - org.geoserver.cloud: DEBUG - org.geoserver.cloud.config.factory: TRACE - org.springframework.test: ERROR - o.s.integration.handler.LoggingHandler: OFF - diff --git a/src/catalog/event-bus/README.md b/src/catalog/event-bus/README.md index 41e53901a..9ae4f3201 100644 --- a/src/catalog/event-bus/README.md +++ b/src/catalog/event-bus/README.md @@ -74,7 +74,7 @@ Instead, the actions to be taken upon receiving remote notification events will May the configuration backend type and topology require receiving either the full object, the diff changes (open "modify" events), or both; it's up to the `GeoServerBackendConfigurer` to complain if sending the required event payload is not enabled. -There're basically two major backend topologies, regardless of the actual implementation (e.g. "data directory", "jdbcconfig", "catalog-service", etc): +There're basically two major backend topologies, regardless of the actual implementation (e.g. "data directory", "jdbcconfig", "pgconfig", etc): - shared catalog: The catalog/config stores are shared among all geoserver services, hence typically the event payload would not be required; - catalog-per-service: each service instance holds on its own copy of the catalog and config objects, hence typically the remote configuration events should carry the object and/or diff payloads to keep the local version of the catalog and config in sync. diff --git a/src/catalog/pom.xml b/src/catalog/pom.xml index 5cb7dae5c..8389f1e23 100644 --- a/src/catalog/pom.xml +++ b/src/catalog/pom.xml @@ -25,15 +25,4 @@ test - - - catalog-service - - false - - - catalog-server - - - diff --git a/src/integration-tests/catalog-service-it/README.md b/src/integration-tests/catalog-service-it/README.md deleted file mode 100644 index 16a80787b..000000000 --- a/src/integration-tests/catalog-service-it/README.md +++ /dev/null @@ -1,7 +0,0 @@ -# Catalog-service/client integration tests - -Pure testing project, depends on both `catalog-service` and `catalog-client` -in order to execute the integration tests by running the service on a random port -and calling it through a manually configured `Catalog` backed by the -`catalog-client` implementation. - diff --git a/src/integration-tests/catalog-service-it/pom.xml b/src/integration-tests/catalog-service-it/pom.xml deleted file mode 100644 index 3baf79719..000000000 --- a/src/integration-tests/catalog-service-it/pom.xml +++ /dev/null @@ -1,71 +0,0 @@ - - - 4.0.0 - - org.geoserver.cloud - integration-tests - ${revision} - - gs-cloud-catalog-service-it - jar - Catalog client/server integration tests - - ${skipTests} - ${skipTests} - - - - org.geoserver.cloud.catalog.service - gs-cloud-reactive-catalog-client - test - - - org.geoserver.cloud.apps - gs-cloud-catalog-service - ${project.version} - test - - - - org.geoserver - gs-main - ${gs.version} - test-jar - test - - - - org.geoserver.cloud.catalog - gs-cloud-catalog-plugin - ${project.version} - test-jar - test - - - com.h2database - h2 - test - - - - - - org.apache.maven.plugins - maven-surefire-plugin - - ${surefire.skip} - - - - org.apache.maven.plugins - maven-failsafe-plugin - - ${failsafe.skip} - 1 - false - false - - - - - diff --git a/src/integration-tests/catalog-service-it/src/test/java/org/geoserver/cloud/catalog/client/reactivefeign/AbstractCatalogServiceClientRepositoryTest.java b/src/integration-tests/catalog-service-it/src/test/java/org/geoserver/cloud/catalog/client/reactivefeign/AbstractCatalogServiceClientRepositoryTest.java deleted file mode 100644 index 09fead422..000000000 --- a/src/integration-tests/catalog-service-it/src/test/java/org/geoserver/cloud/catalog/client/reactivefeign/AbstractCatalogServiceClientRepositoryTest.java +++ /dev/null @@ -1,246 +0,0 @@ -/* - * (c) 2020 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.cloud.catalog.client.reactivefeign; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertNotNull; -import static org.junit.jupiter.api.Assertions.assertNotSame; -import static org.junit.jupiter.api.Assertions.assertNull; -import static org.junit.jupiter.api.Assertions.assertTrue; -import java.io.IOException; -import java.lang.reflect.Proxy; -import java.util.Arrays; -import java.util.Set; -import java.util.function.BiConsumer; -import java.util.function.Consumer; -import java.util.function.Function; -import java.util.function.Supplier; -import java.util.stream.Collectors; -import java.util.stream.Stream; -import org.geoserver.catalog.Catalog; -import org.geoserver.catalog.CatalogInfo; -import org.geoserver.catalog.CatalogTestData; -import org.geoserver.catalog.impl.ClassMappings; -import org.geoserver.catalog.impl.ModificationProxy; -import org.geoserver.catalog.plugin.CatalogInfoRepository; -import org.geoserver.catalog.plugin.Patch; -import org.geoserver.catalog.plugin.PropertyDiff; -import org.geoserver.catalog.plugin.Query; -import org.geoserver.cloud.catalog.app.CatalogServiceApplication; -import org.geoserver.cloud.catalog.client.impl.CatalogClientCatalogFacade; -import org.geoserver.cloud.catalog.client.impl.CatalogClientConfiguration; -import org.geoserver.cloud.catalog.client.impl.InnerResolvingProxy; -import org.geotools.filter.text.cql2.CQLException; -import org.geotools.filter.text.ecql.ECQL; -import org.junit.jupiter.api.AfterEach; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.geotools.api.filter.Filter; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Qualifier; -import org.springframework.boot.autoconfigure.EnableAutoConfiguration; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.boot.test.context.SpringBootTest.WebEnvironment; -import org.springframework.test.context.ActiveProfiles; -import lombok.NonNull; - -@SpringBootTest(classes = { // - CatalogServiceApplication.class, // - CatalogClientConfiguration.class // -}, webEnvironment = WebEnvironment.DEFINED_PORT, - properties = {"reactive.feign.hystrix.enabled=false", - "spring.cloud.circuitbreaker.hystrix.enabled=false", - "spring.main.web-application-type=reactive", "server.port=15556", - "geoserver.backend.catalog-service.uri=http://localhost:${server.port}"}) -@ActiveProfiles("it.catalog-service") -@EnableAutoConfiguration -public abstract class AbstractCatalogServiceClientRepositoryTest> { - - /** - * WebFlux catalog-service catalog with backend as configured by - * bootstrap-it.catalog-service.yml - */ - protected @Autowired @Qualifier("catalog") Catalog serverCatalog; - - private @Autowired CatalogClientCatalogFacade rawCatalogServiceFacade; - - protected CatalogTestData testData; - - protected final @NonNull Class infoType; - - protected InnerResolvingProxy proxyResolver; - - protected AbstractCatalogServiceClientRepositoryTest(@NonNull Class infoType) { - this.infoType = infoType; - } - - public @BeforeEach void setup() { - testData = CatalogTestData.initialized(() -> serverCatalog, () -> null).initConfig(false) - .initialize(); - this.proxyResolver = new InnerResolvingProxy(rawCatalogServiceFacade, null); - // proxyResolver = new ProxyUtils(catalog, geoServer).failOnMissingReference(true); - // clientCatalog = new CatalogImpl(clientFacade); - } - - /** Prune the server catalog */ - public @AfterEach void tearDown() { - testData.deleteAll(serverCatalog); - } - - protected abstract CL repository(); - - public abstract @Test void testFindAll(); - - public abstract @Test void testFindAllByType(); - - public abstract @Test void testFindById(); - - public abstract @Test void testQueryFilter(); - - protected void testFind(Supplier> command, - @SuppressWarnings("unchecked") C... expected) { - - Set expectedIds = - Arrays.stream(expected).map(CatalogInfo::getId).collect(Collectors.toSet()); - Set actual = command.get().map(CatalogInfo::getId).collect(Collectors.toSet()); - assertEquals(expectedIds, actual); - } - - protected void testFindAll(@SuppressWarnings("unchecked") C... expected) { - testFind(() -> repository().findAll(), expected); - } - - protected void testFindAllIncludeFilter(Class type, - @SuppressWarnings("unchecked") S... expected) { - - testFind(() -> repository().findAll(Query.all(type)), expected); - } - - protected void testQueryFilter(String ecqlFilter, - @SuppressWarnings("unchecked") S... expected) { - testQueryFilter(this.infoType, ecqlFilter, expected); - } - - protected void testQueryFilter(Class type, String ecqlFilter, - @SuppressWarnings("unchecked") S... expected) { - Filter filter; - try { - filter = ECQL.toFilter(ecqlFilter); - } catch (CQLException e) { - throw new RuntimeException(e); - } - this.testQueryFilter(type, filter, expected); - } - - protected void testQueryFilter(Class type, Filter filter, - @SuppressWarnings("unchecked") S... expected) { - - Query query = Query.valueOf(type, filter); - Stream found = repository().findAll(query); - - Set expectedIds = - Arrays.stream(expected).map(CatalogInfo::getId).collect(Collectors.toSet()); - Set returnedIds = found.map(CatalogInfo::getId).collect(Collectors.toSet()); - assertEquals(expectedIds, returnedIds); - } - - protected void testFindById(C expected) { - assertNotNull(expected.getId()); - C responseBody = repository().findById(expected.getId(), infoType).get(); - C resolved = resolveProxies(responseBody); - assertCatalogInfoEquals(expected, resolved); - } - - protected I resolveProxies(I info) { - return proxyResolver.resolve(info); - } - - protected final void assertCatalogInfoEquals(C expected, C actual) { - assertPropertriesEqual(expected, actual); - } - - /** - * Subclasses should override to provide {@link CatalogInfo} subtype specific assertions. Not - * doing {@code assertEquals(expected, actual)} because the returned object may differ from the - * submitted one as the catalog populated default properties - */ - protected abstract void assertPropertriesEqual(C expected, C actual); - - @Test void testFindByIdNotFound() throws IOException { - assertTrue(repository().findById("non-existent-ws-id", infoType).isEmpty()); - } - - protected void crudTest(final C toCreate, Function catalogLookup, - Consumer modifyingConsumer, BiConsumer updateVerifier) { - - C created = testCreate(toCreate, catalogLookup); - - C updated = testUpdate(created, modifyingConsumer, updateVerifier); - - testDelete(updated, catalogLookup); - } - - protected C testUpdate(C created, Consumer modifyingConsumer, - BiConsumer updateVerifier) { - - Patch patch = createPatch(created, modifyingConsumer); - C updated = repository().update(created, patch); - assertNotSame(created, updated); - updated = resolveProxies(updated); - updateVerifier.accept(created, updated); - - C foundAfterUpdate = repository().findById(updated.getId(), infoType).get(); - foundAfterUpdate = resolveProxies(foundAfterUpdate); - updateVerifier.accept(created, foundAfterUpdate); - - return updated; - } - - public Patch createPatch(C info, Consumer modifyingConsumer) { - C real = ModificationProxy.unwrap(info); - Class clazz = real.getClass(); - ClassMappings classMappings = ClassMappings.fromImpl(clazz); - - @SuppressWarnings("unchecked") - Class ifaceType = (Class) classMappings.getInterface(); - C proxied = ModificationProxy.create(info, ifaceType); - - modifyingConsumer.accept(proxied); - ModificationProxy proxy = (ModificationProxy) Proxy.getInvocationHandler(proxied); - Patch patch = PropertyDiff.valueOf(proxy).toPatch(); - return patch; - } - - protected C testCreate(C toCreate, Function catalogLookup) { - final String providedId = toCreate.getId(); - assertNotNull("id must be provided", providedId); - assertNull( - - catalogLookup.apply(toCreate.getId()), - "Object to be created shall not already exist in catalog"); - - repository().add(toCreate); - C created = repository().findById(providedId, infoType).get(); - assertNotNull(created, "Object not found after added: " + toCreate); - created = resolveProxies(created); - assertCatalogInfoEquals(toCreate, created); - return created; - } - - protected C testDelete(final C toDelete, Function catalogLookup) { - - C foundBeforeDelete = repository().findById(toDelete.getId(), infoType).get(); - - assertNotNull(foundBeforeDelete); - repository().remove(toDelete); - assertFalse( - - repository().findById(toDelete.getId(), infoType).isPresent(), - "object not deleted from backend catalog"); - - return foundBeforeDelete; - } -} diff --git a/src/integration-tests/catalog-service-it/src/test/java/org/geoserver/cloud/catalog/client/reactivefeign/LayerGroupRepositoryTest.java b/src/integration-tests/catalog-service-it/src/test/java/org/geoserver/cloud/catalog/client/reactivefeign/LayerGroupRepositoryTest.java deleted file mode 100644 index 6c8e9418f..000000000 --- a/src/integration-tests/catalog-service-it/src/test/java/org/geoserver/cloud/catalog/client/reactivefeign/LayerGroupRepositoryTest.java +++ /dev/null @@ -1,236 +0,0 @@ -/* - * (c) 2020 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.cloud.catalog.client.reactivefeign; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertNull; -import static org.junit.jupiter.api.Assertions.assertTrue; -import org.geoserver.catalog.LayerGroupInfo; -import org.geoserver.catalog.LayerInfo; -import org.geoserver.catalog.StyleInfo; -import org.geoserver.catalog.WorkspaceInfo; -import org.geoserver.catalog.plugin.CatalogInfoRepository.LayerGroupRepository; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.geotools.api.filter.Filter; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.autoconfigure.EnableAutoConfiguration; -import lombok.Getter; -import lombok.experimental.Accessors; - -@EnableAutoConfiguration -@Accessors(fluent = true) -class LayerGroupRepositoryTest - extends AbstractCatalogServiceClientRepositoryTest { - - private @Autowired @Getter LayerGroupRepository repository; - - LayerGroupInfo lg1WorkspaceA; - LayerGroupInfo lg2WorkspaceA; - - public LayerGroupRepositoryTest() { - super(LayerGroupInfo.class); - } - - public @BeforeEach void before() { - lg1WorkspaceA = - testData.createLayerGroup( - "lg1wsA-id", - testData.workspaceA, - "lg1wsA", - testData.layerFeatureTypeA, - testData.style2); - lg2WorkspaceA = - testData.createLayerGroup( - "lg2wsA-id", - testData.workspaceA, - "lg2wsA", - testData.layerFeatureTypeA, - (StyleInfo) null); - } - - protected @Override void assertPropertriesEqual( - LayerGroupInfo expected, LayerGroupInfo actual) { - assertEquals(expected.getWorkspace(), actual.getWorkspace()); - assertEquals(expected.getName(), actual.getName()); - assertEquals(expected.isAdvertised(), actual.isAdvertised()); - assertEquals(expected.getLayers(), actual.getLayers()); - } - - @Override public @Test void testFindAll() { - super.testFindAll(testData.layerGroup1); - serverCatalog.add(lg1WorkspaceA); - super.testFindAll(testData.layerGroup1, lg1WorkspaceA); - } - - @Override public @Test void testFindById() { - super.testFindById(testData.layerGroup1); - } - - @Override public @Test void testFindAllByType() { - testFindAll(testData.layerGroup1); - } - - @Override public @Test void testQueryFilter() { - LayerGroupInfo lg1 = testData.layerGroup1; - serverCatalog.add(lg1WorkspaceA); - - super.testQueryFilter(LayerGroupInfo.class, Filter.INCLUDE, lg1, lg1WorkspaceA); - super.testQueryFilter(LayerGroupInfo.class, Filter.EXCLUDE); - - String cql = String.format("\"workspace.name\" = '%s'", testData.workspaceA.getName()); - super.testQueryFilter(cql, lg1WorkspaceA); - - cql = "\"workspace.name\" IS NULL"; - super.testQueryFilter(cql, lg1); - } - - @Test void testLayerGroupCRUD_NoWorkspace() { - WorkspaceInfo workspace = null; - LayerGroupInfo layerGroup = - testData.createLayerGroup( - "layerGroupCRUD_NoWorkspace", - workspace, - "layerGroupCRUD_NoWorkspace_name", - testData.layerFeatureTypeA, - testData.style2); - crudTest( - layerGroup, - serverCatalog::getLayerGroup, - lg -> { - lg.setEnabled(false); - lg.setTitle("changed title"); - lg.setAbstract("new abstract"); - lg.setAdvertised(false); - }, - (orig, updated) -> { - assertFalse(updated.isEnabled()); - assertFalse(updated.isAdvertised()); - assertEquals("changed title", updated.getTitle()); - assertEquals("new abstract", updated.getAbstract()); - assertEquals(1, orig.getLayers().size()); - assertEquals(1, updated.getLayers().size()); - }); - } - - @Test void testLayerGroupCRUD_Workspace() { - final WorkspaceInfo workspace = testData.workspaceA; - LayerGroupInfo layerGroup = - testData.createLayerGroup( - "layerGroupCRUD_Workspace", - workspace, - "layerGroupCRUD_Workspace_name", - testData.layerFeatureTypeA, - (StyleInfo) null); - crudTest( - layerGroup, - serverCatalog::getLayerGroup, - lg -> { - lg.getStyles().set(0, testData.style1); - }, - (orig, updated) -> { - assertNull(orig.getStyles().get(0)); - assertEquals(testData.style1, updated.getStyles().get(0)); - }); - } - - @Test void testUpdateLayers() { - WorkspaceInfo workspace = null; - LayerGroupInfo layerGroup = - testData.createLayerGroup( - "layerGroupCRUD_NoWorkspace", - workspace, - "layerGroupCRUD_NoWorkspace_name", - testData.layerFeatureTypeA, - testData.style2); - - LayerInfo layer2 = testData.createLayer(testData.coverageA, testData.style1); - serverCatalog.add(layer2); - - crudTest( - layerGroup, - serverCatalog::getLayerGroup, - lg -> { - lg.setEnabled(false); - lg.setTitle("changed title"); - lg.setAbstract("new abstract"); - lg.setAdvertised(false); - lg.getLayers().add(layer2); - lg.getStyles().add(testData.style1); - }, - (orig, updated) -> { - assertFalse(updated.isEnabled()); - assertFalse(updated.isAdvertised()); - assertEquals("changed title", updated.getTitle()); - assertEquals("new abstract", updated.getAbstract()); - assertEquals(1, orig.getLayers().size()); - assertEquals(2, updated.getLayers().size()); - assertEquals(1, orig.getStyles().size()); - assertEquals(2, updated.getStyles().size()); - }); - } - - @Test void testFindAllByWorkspaceIsNull() { - testFind(() -> repository.findAllByWorkspaceIsNull(), testData.layerGroup1); - serverCatalog.add(lg1WorkspaceA); - testFind(() -> repository.findAllByWorkspaceIsNull(), testData.layerGroup1); - LayerGroupInfo lg2 = - testData.createLayerGroup( - "lg2", null, "lg2", testData.layerFeatureTypeA, (StyleInfo) null); - serverCatalog.add(lg2); - testFind(() -> repository.findAllByWorkspaceIsNull(), testData.layerGroup1, lg2); - } - - @Test void testFindAllByWorkspace() { - WorkspaceInfo workspace = testData.workspaceA; - testFind(() -> repository.findAllByWorkspace(testData.workspaceA)); - serverCatalog.add(lg1WorkspaceA); - testFind(() -> repository.findAllByWorkspace(workspace), lg1WorkspaceA); - LayerGroupInfo lg2WorkspaceA = - testData.createLayerGroup( - "lg2", workspace, "lg2", testData.layerFeatureTypeA, (StyleInfo) null); - serverCatalog.add(lg2WorkspaceA); - testFind(() -> repository.findAllByWorkspace(workspace), lg1WorkspaceA, lg2WorkspaceA); - } - - @Test void testFindByNameAndWorkspaceIsNull() { - LayerGroupInfo global = testData.layerGroup1; - assertEquals( - global.getId(), - repository.findByNameAndWorkspaceIsNull(global.getName()).get().getId()); - serverCatalog.add(lg1WorkspaceA); - assertTrue(repository.findByNameAndWorkspaceIsNull(lg1WorkspaceA.getName()).isEmpty()); - } - - @Test void testFindByNameAndWorkspace() { - LayerGroupInfo globalGroup = serverCatalog.getLayerGroup(testData.layerGroup1.getId()); - WorkspaceInfo workspace = testData.workspaceA; - serverCatalog.add(lg1WorkspaceA); - serverCatalog.add(lg2WorkspaceA); - - assertTrue(repository.findByNameAndWorkspace(globalGroup.getName(), workspace).isEmpty()); - - assertEquals( - lg1WorkspaceA.getId(), - repository - .findByNameAndWorkspace(lg1WorkspaceA.getName(), workspace) - .get() - .getId()); - assertEquals( - lg2WorkspaceA.getId(), - repository - .findByNameAndWorkspace(lg2WorkspaceA.getName(), workspace) - .get() - .getId()); - - // workspace and root groups with the same name - globalGroup.setName(lg1WorkspaceA.getName()); - serverCatalog.save(globalGroup); - assertEquals( - lg1WorkspaceA.getId(), - repository.findByNameAndWorkspace(globalGroup.getName(), workspace).get().getId()); - } -} diff --git a/src/integration-tests/catalog-service-it/src/test/java/org/geoserver/cloud/catalog/client/reactivefeign/LayerRepositoryTest.java b/src/integration-tests/catalog-service-it/src/test/java/org/geoserver/cloud/catalog/client/reactivefeign/LayerRepositoryTest.java deleted file mode 100644 index 33c4b9a9c..000000000 --- a/src/integration-tests/catalog-service-it/src/test/java/org/geoserver/cloud/catalog/client/reactivefeign/LayerRepositoryTest.java +++ /dev/null @@ -1,178 +0,0 @@ -/* - * (c) 2020 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.cloud.catalog.client.reactivefeign; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertTrue; -import java.util.Set; -import org.geoserver.catalog.FeatureTypeInfo; -import org.geoserver.catalog.LayerInfo; -import org.geoserver.catalog.StyleInfo; -import org.geoserver.catalog.plugin.CatalogInfoRepository.LayerRepository; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.autoconfigure.EnableAutoConfiguration; -import com.google.common.collect.Sets; -import lombok.Getter; -import lombok.experimental.Accessors; - -@EnableAutoConfiguration -@Accessors(fluent = true) -class LayerRepositoryTest - extends AbstractCatalogServiceClientRepositoryTest { - - private @Autowired @Getter LayerRepository repository; - - private LayerInfo layerFTA; - private LayerInfo layerCVA; - private LayerInfo layerWMTSA; - - public LayerRepositoryTest() { - super(LayerInfo.class); - } - - protected @Override void assertPropertriesEqual(LayerInfo expected, LayerInfo actual) { - assertEquals(expected.getName(), actual.getName()); - assertEquals(expected.getResource().getId(), actual.getResource().getId()); - assertEquals(expected.getDefaultStyle(), actual.getDefaultStyle()); - assertEquals(expected.getStyles(), actual.getStyles()); - } - - public @BeforeEach void removeExisitng() { - // can't create the layer with testData.ft as its resource otherwise, it's a 1:1 - // relationship - serverCatalog.remove(testData.layerGroup1); - serverCatalog.remove(testData.layerFeatureTypeA); - assertTrue(serverCatalog.getLayers().isEmpty()); - - layerFTA = testData.layerFeatureTypeA; - layerCVA = testData.createLayer(testData.coverageA, testData.style2); - layerWMTSA = testData.createLayer(testData.wmtsLayerA, testData.style1); - } - - private void addLayers() { - serverCatalog.add(layerFTA); - serverCatalog.add(layerCVA); - serverCatalog.add(layerWMTSA); - } - - @Override public @Test void testFindAll() { - assertEquals(0, repository.findAll().count()); - addLayers(); - super.testFindAll(layerFTA, layerWMTSA, layerCVA); - } - - @Override public @Test void testFindAllByType() { - testFindAllIncludeFilter(LayerInfo.class); - addLayers(); - testFindAllIncludeFilter(LayerInfo.class, layerFTA, layerCVA, layerWMTSA); - } - - @Override public @Test void testFindById() { - serverCatalog.add(testData.layerFeatureTypeA); - super.testFindById(testData.layerFeatureTypeA); - } - - @Override public @Test void testQueryFilter() { - serverCatalog.add(testData.layerFeatureTypeA); - StyleInfo style1 = testData.style1; - StyleInfo style2 = testData.style2; - StyleInfo style3 = testData.createStyle("style3"); - StyleInfo style4 = testData.createStyle("style4"); - serverCatalog.add(style3); - serverCatalog.add(style4); - - LayerInfo layer1 = serverCatalog.getLayer(testData.layerFeatureTypeA.getId()); - layer1.getStyles().add(style4); - layer1.getStyles().add(style2); - serverCatalog.save(layer1); - LayerInfo layer2 = testData.createLayer("cov-layer-id", testData.coverageA, - "coverage layer", true, style2, style1, style3, style4); - serverCatalog.add(layer1); - serverCatalog.add(layer2); - - String cql = String.format("\"defaultStyle.name\" = '%s'", style1.getName()); - super.testQueryFilter(cql, layer1); - - cql = String.format("\"styles.name\" = '%s'", style4.getName()); - super.testQueryFilter(cql, layer1, layer2); - } - - @Test void testLayerCRUD() { - LayerInfo layer = testData.layerFeatureTypeA; - crudTest(layer, serverCatalog::getLayer, l -> { - l.setDefaultStyle(testData.style2); - }, (orig, updated) -> { - assertEquals(testData.style2, updated.getDefaultStyle()); - }); - } - - @Test void testUpdateStyles() { - LayerInfo layer = testData.layerFeatureTypeA; - serverCatalog.add(layer); - layer = serverCatalog.getLayer(layer.getId()); - - testUpdate(layer, l -> { - // AttributionInfoImpl attribution = new AttributionInfoImpl(); - // attribution.setHref("http://test.com"); - // attribution.setLogoHeight(20); - // attribution.setLogoWidth(10); - // l.setAttribution(attribution); - // l.setPath("/llll"); - l.getStyles().clear(); - l.getStyles().add(testData.style1); - l.getStyles().add(testData.style2); - }, (orig, updated) -> { - assertEquals(2, updated.getStyles().size()); - Set expected = Sets.newHashSet(testData.style2, testData.style1); - assertEquals(expected, updated.getStyles()); - }); - } - - @Test void testFindLayersByResource() { - addLayers(); - - testFind(() -> repository.findAllByResource(layerFTA.getResource()), layerFTA); - testFind(() -> repository.findAllByResource(layerCVA.getResource()), layerCVA); - testFind(() -> repository.findAllByResource(layerWMTSA.getResource()), layerWMTSA); - } - - @Test void testFindLayersByResource_NonExistentResource() { - FeatureTypeInfo missingResource = testData.createFeatureType("not-added-to-catalog"); - - assertEquals(0, repository.findAllByResource(missingResource).count()); - } - - @Test void testFindLayersWithStyle() { - StyleInfo style1 = testData.style1; // on layer1 and layer2 - StyleInfo style2 = testData.style2; // layer2's default style - StyleInfo style3 = testData.createStyle("style3"); // on layer2 - StyleInfo style4 = testData.createStyle("styleWithNoLayerAssociated"); // on no layer - serverCatalog.add(style3); - serverCatalog.add(style4); - - LayerInfo layer1 = testData.layerFeatureTypeA; - LayerInfo layer2 = testData.createLayer("cov-layer-id", testData.coverageA, - "coverage layer", true, style2, style1, style3); - serverCatalog.add(layer1); - serverCatalog.add(layer2); - - testFindLayersWithStyle(style1, layer1, layer2); - testFindLayersWithStyle(style2, layer2); - testFindLayersWithStyle(style3, layer2); - testFindLayersWithStyle(style4); - } - - private void testFindLayersWithStyle(StyleInfo style, LayerInfo... expectedLayers) { - - testFind(() -> repository.findAllByDefaultStyleOrStyles(style), expectedLayers); - } - - @Test void testFindOneByName() { - addLayers(); - assertEquals(layerFTA.getId(), repository.findOneByName(layerFTA.getName()).get().getId()); - } -} diff --git a/src/integration-tests/catalog-service-it/src/test/java/org/geoserver/cloud/catalog/client/reactivefeign/NamespaceRepositoryTest.java b/src/integration-tests/catalog-service-it/src/test/java/org/geoserver/cloud/catalog/client/reactivefeign/NamespaceRepositoryTest.java deleted file mode 100644 index 7e762b2b3..000000000 --- a/src/integration-tests/catalog-service-it/src/test/java/org/geoserver/cloud/catalog/client/reactivefeign/NamespaceRepositoryTest.java +++ /dev/null @@ -1,188 +0,0 @@ -/* - * (c) 2020 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.cloud.catalog.client.reactivefeign; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertNotNull; -import static org.junit.jupiter.api.Assertions.assertNull; -import static org.junit.jupiter.api.Assertions.assertTrue; -import static org.junit.jupiter.api.Assertions.fail; -import java.io.IOException; -import java.util.List; -import java.util.stream.Collectors; -import org.geoserver.catalog.NamespaceInfo; -import org.geoserver.catalog.plugin.CatalogInfoRepository.NamespaceRepository; -import org.junit.jupiter.api.Test; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.autoconfigure.EnableAutoConfiguration; -import lombok.Getter; -import lombok.experimental.Accessors; - -@EnableAutoConfiguration -@Accessors(fluent = true) -class NamespaceRepositoryTest - extends AbstractCatalogServiceClientRepositoryTest { - - private @Autowired @Getter NamespaceRepository repository; - - public NamespaceRepositoryTest() { - super(NamespaceInfo.class); - } - - protected @Override void assertPropertriesEqual(NamespaceInfo expected, NamespaceInfo actual) { - assertEquals(expected.getName(), actual.getName()); - assertEquals(expected.getPrefix(), actual.getPrefix()); - assertEquals(expected.getURI(), actual.getURI()); - } - - @Override public @Test void testFindAll() { - super.testFindAll(testData.namespaceA, testData.namespaceB, testData.namespaceC); - } - - @Override public @Test void testFindAllByType() { - super.testFindAllIncludeFilter(NamespaceInfo.class, testData.namespaceA, - testData.namespaceB, testData.namespaceC); - } - - @Override public @Test void testFindById() { - super.testFindById(testData.namespaceA); - super.testFindById(testData.namespaceB); - super.testFindById(testData.namespaceC); - } - - @Override public @Test void testQueryFilter() { - NamespaceInfo ns1 = serverCatalog.getNamespace(testData.namespaceA.getId()); - NamespaceInfo ns2 = serverCatalog.getNamespace(testData.namespaceB.getId()); - NamespaceInfo ns3 = serverCatalog.getNamespace(testData.namespaceC.getId()); - - super.testQueryFilter(String.format("URI = '%s'", ns2.getURI()), ns2); - - ns3.setIsolated(true); - ns3.setURI(ns1.getURI()); - serverCatalog.save(ns3); - - super.testQueryFilter(String.format("URI = '%s'", ns1.getURI()), ns1, ns3); - } - - @Test void testFindNamespaceById() { - testFindById(testData.namespaceA); - testFindById(testData.namespaceB); - testFindById(testData.namespaceC); - } - - @Test void testFindNamespacePrefix() { - testFindByPrefix(testData.namespaceA); - testFindByPrefix(testData.namespaceB); - testFindByPrefix(testData.namespaceC); - } - - private void testFindByPrefix(NamespaceInfo expected) { - assertEquals(expected, - repository.findFirstByName(expected.getPrefix(), NamespaceInfo.class).get()); - } - - @Test void testNamespaceInfo_CRUD() throws IOException { - NamespaceInfo ns = testData.faker().namespace(); - crudTest(ns, serverCatalog::getNamespace, n -> n.setPrefix("modified-prefix"), - (old, updated) -> assertEquals("modified-prefix", updated.getPrefix())); - } - - @Test void testGetDefaultNamespace() { - assertEquals(testData.namespaceA, repository.getDefaultNamespace().get()); - serverCatalog.setDefaultNamespace(testData.namespaceB); - assertEquals(testData.namespaceB, repository.getDefaultNamespace().get()); - } - - @Test void testGetDefaultNamespaceNoDefaultExists() { - testData.deleteAll(); - assertNull(serverCatalog.getDefaultNamespace()); - assertTrue(repository.getDefaultNamespace().isEmpty()); - } - - @Test void testSetDefaultNamespace() { - assertEquals(testData.namespaceA, serverCatalog.getDefaultNamespace()); - - repository.setDefaultNamespace(testData.namespaceB); - NamespaceInfo returned = repository.getDefaultNamespace().get(); - assertEquals(testData.namespaceB, returned); - assertEquals(testData.namespaceB, serverCatalog.getDefaultNamespace()); - } - - @Test void testSetDefaultNamespaceNonExistent() { - assertEquals(testData.namespaceA, serverCatalog.getDefaultNamespace()); - - NamespaceInfo nonExistent = testData.faker().namespace(); - repository.setDefaultNamespace(nonExistent); - assertEquals(testData.namespaceA, repository.getDefaultNamespace().get()); - assertEquals(testData.namespaceA, serverCatalog.getDefaultNamespace()); - } - - @Test void testUnsetDefaultNamespace() { - NamespaceInfo ns = testData.namespaceA; - // preflight check - serverCatalog.setDefaultNamespace(null); - assertNull(serverCatalog.getDefaultNamespace()); - serverCatalog.setDefaultNamespace(ns); - assertEquals(ns, serverCatalog.getDefaultNamespace()); - - NamespaceInfo current = serverCatalog.getDefaultNamespace(); - assertNotNull(current); - assertEquals(ns.getId(), current.getId()); - - repository.unsetDefaultNamespace(); - - assertNull(serverCatalog.getDefaultNamespace()); - assertTrue(repository.getDefaultNamespace().isEmpty()); - - // check idempotency - repository.unsetDefaultNamespace(); - - assertNull(serverCatalog.getDefaultNamespace()); - assertTrue(repository.getDefaultNamespace().isEmpty()); - } - - @Test void testFindOneNamespaceByURI() { - NamespaceInfo ns1 = testData.namespaceA; - NamespaceInfo ns2 = testData.faker().namespace(); - ns2.setURI(ns1.getURI()); - ns2.setIsolated(true); - serverCatalog.add(ns2); - - NamespaceInfo found = repository.findOneByURI(ns1.getURI()).get(); - // serverCatalog.getNamespaceByURI() contract says it returns the first found with that - // uri... - assertTrue(found.getId().equals(ns1.getId()) || found.getId().equals(ns2.getId())); - } - - @Test void testFindAllNamespacesByURI() { - NamespaceInfo ns1 = testData.namespaceA; - NamespaceInfo ns2 = testData.faker().namespace(); - ns2.setURI(ns1.getURI()); - ns2.setIsolated(true); - serverCatalog.add(ns2); - - List found = - repository.findAllByURI(ns1.getURI()).collect(Collectors.toList()); - assertTrue(found.contains(ns1)); - assertTrue(found.contains(ns2)); - assertEquals(2, found.size()); - } - - @Test void testCreateNamespaceDuplicateURI() { - NamespaceInfo ns1 = testData.namespaceA; - NamespaceInfo ns2 = testData.faker().namespace(); - ns2.setURI(ns1.getURI()); - try { - repository.add(ns2); - fail("expected exception"); - } catch (RuntimeException expected) { - expected.printStackTrace(); - } - - ns2.setIsolated(true); - repository.add(ns2); - assertEquals(ns2, repository.findById(ns2.getId(), NamespaceInfo.class).get()); - } -} diff --git a/src/integration-tests/catalog-service-it/src/test/java/org/geoserver/cloud/catalog/client/reactivefeign/ResourceRepositoryTest.java b/src/integration-tests/catalog-service-it/src/test/java/org/geoserver/cloud/catalog/client/reactivefeign/ResourceRepositoryTest.java deleted file mode 100644 index edaa41cbf..000000000 --- a/src/integration-tests/catalog-service-it/src/test/java/org/geoserver/cloud/catalog/client/reactivefeign/ResourceRepositoryTest.java +++ /dev/null @@ -1,305 +0,0 @@ -/* - * (c) 2020 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.cloud.catalog.client.reactivefeign; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertTrue; -import java.io.IOException; -import java.util.List; -import java.util.stream.Collectors; -import org.geoserver.catalog.CoverageInfo; -import org.geoserver.catalog.CoverageStoreInfo; -import org.geoserver.catalog.DataStoreInfo; -import org.geoserver.catalog.FeatureTypeInfo; -import org.geoserver.catalog.NamespaceInfo; -import org.geoserver.catalog.ResourceInfo; -import org.geoserver.catalog.WMSLayerInfo; -import org.geoserver.catalog.WMTSLayerInfo; -import org.geoserver.catalog.impl.WMSLayerInfoImpl; -import org.geoserver.catalog.plugin.CatalogInfoRepository.ResourceRepository; -import org.geoserver.catalog.plugin.Query; -import org.geoserver.ows.util.OwsUtils; -import org.junit.jupiter.api.Disabled; -import org.junit.jupiter.api.Test; -import org.geotools.api.filter.Filter; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.autoconfigure.EnableAutoConfiguration; -import lombok.Getter; -import lombok.experimental.Accessors; - -@EnableAutoConfiguration -@Accessors(fluent = true) -class ResourceRepositoryTest - extends AbstractCatalogServiceClientRepositoryTest { - - private @Autowired @Getter ResourceRepository repository; - - public ResourceRepositoryTest() { - super(ResourceInfo.class); - } - - protected @Override void assertPropertriesEqual(ResourceInfo expected, ResourceInfo actual) { - assertEquals(expected.getAbstract(), actual.getAbstract()); - assertEquals(expected.getTitle(), actual.getTitle()); - assertEquals(expected.isEnabled(), actual.isEnabled()); - assertEquals(expected.isAdvertised(), actual.isAdvertised()); - assertEquals(expected.getDescription(), actual.getDescription()); - assertEquals(expected.getStore().getId(), actual.getStore().getId()); - } - - @Override public @Test void testFindAll() { - super.testFindAll( - testData.featureTypeA, testData.coverageA, testData.wmsLayerA, testData.wmtsLayerA); - } - - @Override public @Test void testFindById() { - super.testFindById(testData.featureTypeA); - super.testFindById(testData.coverageA); - super.testFindById(testData.wmsLayerA); - super.testFindById(testData.wmtsLayerA); - } - - @Override public @Test void testFindAllByType() { - super.testFindAllIncludeFilter( - ResourceInfo.class, - testData.featureTypeA, - testData.coverageA, - testData.wmsLayerA, - testData.wmtsLayerA); - super.testFindAllIncludeFilter(FeatureTypeInfo.class, testData.featureTypeA); - super.testFindAllIncludeFilter(CoverageInfo.class, testData.coverageA); - super.testFindAllIncludeFilter(WMSLayerInfo.class, testData.wmsLayerA); - super.testFindAllIncludeFilter(WMTSLayerInfo.class, testData.wmtsLayerA); - } - - @Test void testFindAllByNamespace() { - testFind( - () -> repository.findAllByNamespace(testData.namespaceA, ResourceInfo.class), - testData.featureTypeA, - testData.coverageA, - testData.wmsLayerA, - testData.wmtsLayerA); - - testFind( - () -> repository.findAllByNamespace(testData.namespaceA, FeatureTypeInfo.class), - testData.featureTypeA); - } - - @Test void testFindByStoreAndName() { - DataStoreInfo ds = testData.dataStoreA; - FeatureTypeInfo ft = testData.featureTypeA; - CoverageStoreInfo cs = testData.coverageStoreA; - CoverageInfo cv = testData.coverageA; - - assertEquals( - ft.getId(), - repository.findByStoreAndName(ds, ft.getName(), ResourceInfo.class).get().getId()); - assertEquals( - ft.getId(), - repository - .findByStoreAndName(ds, ft.getName(), FeatureTypeInfo.class) - .get() - .getId()); - assertTrue(repository.findByStoreAndName(ds, ft.getName(), CoverageInfo.class).isEmpty()); - - assertEquals( - cv.getId(), - repository.findByStoreAndName(cs, cv.getName(), ResourceInfo.class).get().getId()); - assertEquals( - cv.getId(), - repository.findByStoreAndName(cs, cv.getName(), CoverageInfo.class).get().getId()); - assertTrue( - repository.findByStoreAndName(cs, cv.getName(), FeatureTypeInfo.class).isEmpty()); - } - - @Test void testFindAllByStore() { - FeatureTypeInfo ftA2 = testData.createFeatureType("ftA2"); - CoverageInfo cvA2 = testData.createCoverage("cvA2"); - serverCatalog.add(ftA2); - serverCatalog.add(cvA2); - - testFind( - () -> repository.findAllByStore(testData.dataStoreA, FeatureTypeInfo.class), - testData.featureTypeA, - ftA2); - testFind(() -> repository.findAllByStore(testData.dataStoreA, CoverageInfo.class)); - - testFind( - () -> repository.findAllByStore(testData.coverageStoreA, CoverageInfo.class), - testData.coverageA, - cvA2); - testFind(() -> repository.findAllByStore(testData.coverageStoreA, FeatureTypeInfo.class)); - } - - @Override public @Test void testQueryFilter() { - FeatureTypeInfo ft = serverCatalog.getFeatureType(testData.featureTypeA.getId()); - CoverageInfo cv = serverCatalog.getCoverage(testData.coverageA.getId()); - WMSLayerInfo wms = - serverCatalog.getResource(testData.wmsLayerA.getId(), WMSLayerInfo.class); - WMTSLayerInfo wmts = - serverCatalog.getResource(testData.wmtsLayerA.getId(), WMTSLayerInfo.class); - - wms.setEnabled(false); - wmts.setEnabled(false); - cv.setEnabled(true); - serverCatalog.save(wms); - serverCatalog.save(wmts); - serverCatalog.save(cv); - - super.testQueryFilter(ResourceInfo.class, Filter.INCLUDE, ft, cv, wms, wmts); - super.testQueryFilter(CoverageInfo.class, Filter.INCLUDE, cv); - super.testQueryFilter("enabled = true", ft, cv); - super.testQueryFilter("enabled = false", wms, wmts); - } - - @Test void testResourceInfoCRUD_FeatureTypeInfo() { - FeatureTypeInfo toCreate = - testData.createFeatureType( - "featureTypeCRUD", - testData.dataStoreC, - testData.namespaceC, - "featureTypeCRUD_name", - "featureTypeCRUD abs", - "featureTypeCRUD desc", - true); - crudTest( - toCreate, - serverCatalog::getFeatureType, - created -> { - created.setEnabled(!created.isEnabled()); - created.setName("modified ft name"); - created.setDescription("new description"); - }, - (orig, updated) -> { - assertFalse(updated.isEnabled()); - assertEquals("modified ft name", updated.getName()); - assertEquals("new description", updated.getDescription()); - }); - } - - @Test void testResourceInfoCRUD_CoverageInfo() { - CoverageInfo toCreate = - testData.createCoverage( - "coverageCRUD", testData.coverageStoreA, "coverageCRUD_name"); - crudTest( - toCreate, - serverCatalog::getCoverage, - created -> { - created.setEnabled(false); - created.setName("modified coverage name"); - created.setDescription("new description"); - }, - (orig, updated) -> { - assertFalse(updated.isEnabled()); - assertEquals("modified coverage name", updated.getName()); - assertEquals("new description", updated.getDescription()); - }); - } - - /** - * Horror here, ignored because {@link OwsUtils#copy} tries to connect to the real WMS service - * as calls {@link WMSLayerInfoImpl#getRemoteStyleInfos()} (fault is on WMSLayerInfo having a - * getter name for a method that does I/O). - * - *

{@code java.lang.IllegalAccessException: class - * org.geoserver.catalog.impl.ModificationProxyCloner cannot access a member of class - * java.util.Collections$EmptySet (in module java.base) with modifiers "private"} - */ - @Disabled - @Test void testResourceInfoCRUD_WMSLayerInfo() { - WMSLayerInfo toCreate = - testData.createWMSLayer( - "wmsLayerCRUD", - testData.wmsStoreA, - testData.namespaceA, - "wmsLayerCRUD_name", - false); - crudTest( - toCreate, - id -> serverCatalog.getResource(id, WMSLayerInfo.class), - created -> { - created.setEnabled(false); - created.setName("modified wms layer name"); - created.setDescription("new description"); - }, - (orig, updated) -> { - assertFalse(updated.isEnabled()); - assertEquals("modified wms layer name", updated.getName()); - assertEquals("new description", updated.getDescription()); - }); - } - - @Test void testResourceInfoCRUD_WMTSLayerInfo() { - WMTSLayerInfo toCreate = - testData.createWMTSLayer( - "wmtsLayerCRUD", - testData.wmtsStoreA, - testData.namespaceA, - "wmtsLayerCRUD_name", - false); - crudTest( - toCreate, - id -> serverCatalog.getResource(id, WMTSLayerInfo.class), - created -> { - created.setEnabled(false); - created.setName("modified wtms layer name"); - created.setDescription("new description"); - }, - (orig, updated) -> { - assertFalse(updated.isEnabled()); - assertEquals("modified wtms layer name", updated.getName()); - assertEquals("new description", updated.getDescription()); - }); - } - - @Test void testFindResourceInfoById() { - testFindById(testData.featureTypeA); - testFindById(testData.coverageA); - testFindById(testData.wmsLayerA); - testFindById(testData.wmtsLayerA); - } - - @Test void testFindResourceInfoById_SubtypeMismatch() throws IOException { - ResourceRepository client = repository; - assertTrue(client.findById(testData.featureTypeA.getId(), CoverageInfo.class).isEmpty()); - assertTrue(client.findById(testData.coverageA.getId(), FeatureTypeInfo.class).isEmpty()); - assertTrue(client.findById(testData.wmsLayerA.getId(), WMTSLayerInfo.class).isEmpty()); - assertTrue(client.findById(testData.wmtsLayerA.getId(), WMSLayerInfo.class).isEmpty()); - } - - @Test void testFindResourceByNamespaceIdAndName() { - NamespaceInfo ns = testData.namespaceA; - ResourceInfo ftA = testData.featureTypeA; - - ResourceRepository client = repository; - String name = ftA.getName(); - - assertEquals( - ftA.getId(), - client.findByNameAndNamespace(name, ns, ResourceInfo.class).get().getId()); - assertEquals( - ftA.getId(), - client.findByNameAndNamespace(name, ns, FeatureTypeInfo.class).get().getId()); - assertTrue(client.findByNameAndNamespace(name, ns, CoverageInfo.class).isEmpty()); - } - - @Test void testFindAllBySubtype() { - ResourceRepository client = repository; - - List all = - client.findAll(Query.all(FeatureTypeInfo.class)).collect(Collectors.toList()); - assertEquals(serverCatalog.getResources(FeatureTypeInfo.class).size(), all.size()); - - all = client.findAll(Query.all(CoverageInfo.class)).collect(Collectors.toList()); - assertEquals(serverCatalog.getResources(CoverageInfo.class).size(), all.size()); - - all = client.findAll(Query.all(WMSLayerInfo.class)).collect(Collectors.toList()); - assertEquals(serverCatalog.getResources(WMSLayerInfo.class).size(), all.size()); - - all = client.findAll(Query.all(WMTSLayerInfo.class)).collect(Collectors.toList()); - assertEquals(serverCatalog.getResources(WMTSLayerInfo.class).size(), all.size()); - } -} diff --git a/src/integration-tests/catalog-service-it/src/test/java/org/geoserver/cloud/catalog/client/reactivefeign/StoreRepositoryTest.java b/src/integration-tests/catalog-service-it/src/test/java/org/geoserver/cloud/catalog/client/reactivefeign/StoreRepositoryTest.java deleted file mode 100644 index 980184caf..000000000 --- a/src/integration-tests/catalog-service-it/src/test/java/org/geoserver/cloud/catalog/client/reactivefeign/StoreRepositoryTest.java +++ /dev/null @@ -1,441 +0,0 @@ -/* - * (c) 2020 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.cloud.catalog.client.reactivefeign; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertNotNull; -import static org.junit.jupiter.api.Assertions.assertNull; -import static org.junit.jupiter.api.Assertions.assertTrue; -import java.io.IOException; -import java.io.Serializable; -import java.util.Arrays; -import java.util.HashMap; -import java.util.Map; -import java.util.Set; -import java.util.stream.Collectors; -import java.util.stream.Stream; -import org.geoserver.catalog.CascadeDeleteVisitor; -import org.geoserver.catalog.CoverageStoreInfo; -import org.geoserver.catalog.DataStoreInfo; -import org.geoserver.catalog.HTTPStoreInfo; -import org.geoserver.catalog.NamespaceInfo; -import org.geoserver.catalog.StoreInfo; -import org.geoserver.catalog.WMSStoreInfo; -import org.geoserver.catalog.WMTSStoreInfo; -import org.geoserver.catalog.WorkspaceInfo; -import org.geoserver.catalog.plugin.CatalogInfoRepository.StoreRepository; -import org.junit.jupiter.api.Test; -import org.geotools.api.filter.Filter; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.autoconfigure.EnableAutoConfiguration; -import lombok.Getter; -import lombok.experimental.Accessors; - -@EnableAutoConfiguration -@Accessors(fluent = true) -class StoreRepositoryTest - extends AbstractCatalogServiceClientRepositoryTest { - - private @Autowired @Getter StoreRepository repository; - - public StoreRepositoryTest() { - super(StoreInfo.class); - } - - protected @Override void assertPropertriesEqual(StoreInfo expected, StoreInfo actual) { - assertEquals(expected.getName(), actual.getName()); - assertEquals(expected.getDescription(), actual.getDescription()); - // connection params may have been serialized as string - final Map cm1 = - expected.getConnectionParameters() == null - ? new HashMap<>() - : expected.getConnectionParameters(); - final Map cm2 = - actual.getConnectionParameters() == null - ? new HashMap<>() - : actual.getConnectionParameters(); - assertEquals(cm1.size(), cm2.size()); - cm1.forEach((k, v) -> assertEquals(String.valueOf(v), String.valueOf(cm2.get(k)))); - assertEquals(expected.getType(), actual.getType()); - assertEquals(expected.getWorkspace(), actual.getWorkspace()); - assertEquals(expected.isEnabled(), actual.isEnabled()); - if (expected instanceof CoverageStoreInfo cov) - assertEquals( - cov.getURL(), ((CoverageStoreInfo) actual).getURL()); - if (expected instanceof HTTPStoreInfo httpStore) - assertEquals( - httpStore.getCapabilitiesURL(), - ((HTTPStoreInfo) actual).getCapabilitiesURL()); - } - - @Override public @Test void testFindAll() { - super.testFindAll( - testData.dataStoreA, - testData.dataStoreB, - testData.dataStoreC, - testData.coverageStoreA, - testData.wmsStoreA, - testData.wmtsStoreA); - } - - @Override public @Test void testFindById() { - super.testFindById(testData.dataStoreA); - super.testFindById(testData.coverageStoreA); - super.testFindById(testData.wmsStoreA); - super.testFindById(testData.wmtsStoreA); - } - - @Override public @Test void testFindAllByType() { - super.testFindAllIncludeFilter( - StoreInfo.class, - testData.dataStoreA, - testData.dataStoreB, - testData.dataStoreC, - testData.coverageStoreA, - testData.wmsStoreA, - testData.wmtsStoreA); - - super.testFindAllIncludeFilter( - DataStoreInfo.class, testData.dataStoreA, testData.dataStoreB, testData.dataStoreC); - super.testFindAllIncludeFilter(CoverageStoreInfo.class, testData.coverageStoreA); - super.testFindAllIncludeFilter(WMSStoreInfo.class, testData.wmsStoreA); - super.testFindAllIncludeFilter(WMTSStoreInfo.class, testData.wmtsStoreA); - } - - @Test void testFindAllByTypeStoreRepository() { - testFind( - () -> repository.findAllByType(StoreInfo.class), - testData.dataStoreA, - testData.dataStoreB, - testData.dataStoreC, - testData.coverageStoreA, - testData.wmsStoreA, - testData.wmtsStoreA); - - testFind( - () -> repository.findAllByType(DataStoreInfo.class), - testData.dataStoreA, - testData.dataStoreB, - testData.dataStoreC); - - testFind(() -> repository.findAllByType(CoverageStoreInfo.class), testData.coverageStoreA); - testFind(() -> repository.findAllByType(WMSStoreInfo.class), testData.wmsStoreA); - testFind(() -> repository.findAllByType(WMTSStoreInfo.class), testData.wmtsStoreA); - } - - @Test void testSetDefaultDataStore() { - WorkspaceInfo ws = testData.workspaceA; - DataStoreInfo ds1 = testData.dataStoreA; - DataStoreInfo ds2 = testData.faker().dataStoreInfo("wsA-ds2", ws); - serverCatalog.add(ds2); - assertEquals(ds1.getId(), repository().getDefaultDataStore(ws).get().getId()); - - repository().setDefaultDataStore(ws, ds2); - assertEquals(ds2.getId(), repository().getDefaultDataStore(ws).get().getId()); - assertEquals(ds2.getId(), serverCatalog.getDefaultDataStore(ws).getId()); - } - - @Test void testUnsetDefaultDataStore() { - WorkspaceInfo ws = testData.workspaceA; - DataStoreInfo store = testData.dataStoreA; - // preflight check - serverCatalog.setDefaultDataStore(ws, null); - assertNull(serverCatalog.getDefaultDataStore(ws)); - serverCatalog.setDefaultDataStore(ws, store); - assertEquals(store, serverCatalog.getDefaultDataStore(ws)); - - DataStoreInfo current = serverCatalog.getDefaultDataStore(ws); - assertNotNull(current); - assertEquals(store.getId(), current.getId()); - - repository.unsetDefaultDataStore(ws); - - assertNull(serverCatalog.getDefaultDataStore(ws)); - assertTrue(repository.getDefaultDataStore(ws).isEmpty()); - - // check idempotency - repository.unsetDefaultDataStore(ws); - - assertNull(serverCatalog.getDefaultDataStore(ws)); - assertTrue(repository.getDefaultDataStore(ws).isEmpty()); - } - - @Test void getDefaultDataStore() { - WorkspaceInfo wsA = testData.workspaceA; - WorkspaceInfo wsB = testData.workspaceB; - - DataStoreInfo dsA2 = testData.faker().dataStoreInfo("wsA-ds2", wsA); - DataStoreInfo dsB2 = testData.faker().dataStoreInfo("wsB-ds2", wsB); - serverCatalog.add(dsA2); - serverCatalog.add(dsB2); - - StoreRepository repository = repository(); - - assertEquals( - testData.dataStoreA.getId(), repository.getDefaultDataStore(wsA).get().getId()); - assertEquals( - testData.dataStoreB.getId(), repository.getDefaultDataStore(wsB).get().getId()); - - serverCatalog.setDefaultDataStore(wsA, dsA2); - serverCatalog.setDefaultDataStore(wsB, dsB2); - - assertEquals(dsA2.getId(), repository.getDefaultDataStore(wsA).get().getId()); - assertEquals(dsB2.getId(), repository.getDefaultDataStore(wsB).get().getId()); - - CascadeDeleteVisitor cascadeDeleteVisitor = new CascadeDeleteVisitor(serverCatalog); - serverCatalog.getDataStore(testData.dataStoreA.getId()).accept(cascadeDeleteVisitor); - serverCatalog.getDataStore(dsA2.getId()).accept(cascadeDeleteVisitor); - assertNull(serverCatalog.getDefaultDataStore(wsA)); - assertTrue(repository.getDefaultDataStore(wsA).isEmpty()); - } - - @Test void testGetDefaultDataStores() { - WorkspaceInfo wsA = testData.workspaceA; - WorkspaceInfo wsB = testData.workspaceB; - DataStoreInfo dsA2 = testData.faker().dataStoreInfo("wsA-ds2", wsA); - DataStoreInfo dsB2 = testData.faker().dataStoreInfo("wsB-ds2", wsB); - serverCatalog.add(dsA2); - serverCatalog.add(dsB2); - - StoreRepository repository = repository(); - testFind( - () -> repository.getDefaultDataStores(), - testData.dataStoreA, - testData.dataStoreB, - testData.dataStoreC); - - serverCatalog.setDefaultDataStore(wsA, dsA2); - serverCatalog.setDefaultDataStore(wsB, dsB2); - testFind(() -> repository.getDefaultDataStores(), dsA2, dsB2, testData.dataStoreC); - } - - @Override public @Test void testQueryFilter() { - DataStoreInfo ds1 = serverCatalog.getDataStore(testData.dataStoreA.getId()); - DataStoreInfo ds2 = serverCatalog.getDataStore(testData.dataStoreB.getId()); - DataStoreInfo ds3 = serverCatalog.getDataStore(testData.dataStoreC.getId()); - CoverageStoreInfo cs1 = serverCatalog.getCoverageStore(testData.coverageStoreA.getId()); - WMSStoreInfo wmss1 = serverCatalog.getStore(testData.wmsStoreA.getId(), WMSStoreInfo.class); - WMTSStoreInfo wmtss1 = - serverCatalog.getStore(testData.wmtsStoreA.getId(), WMTSStoreInfo.class); - - super.testQueryFilter(StoreInfo.class, Filter.INCLUDE, ds1, ds2, ds3, cs1, wmss1, wmtss1); - super.testQueryFilter(StoreInfo.class, Filter.EXCLUDE); - super.testQueryFilter(DataStoreInfo.class, Filter.INCLUDE, ds1, ds2, ds3); - super.testQueryFilter(CoverageStoreInfo.class, Filter.INCLUDE, cs1); - super.testQueryFilter(WMSStoreInfo.class, Filter.INCLUDE, wmss1); - super.testQueryFilter(WMTSStoreInfo.class, Filter.INCLUDE, wmtss1); - - String ecql = String.format("\"workspace.name\" = '%s'", testData.workspaceA.getName()); - super.testQueryFilter(ecql, ds1, cs1, wmss1, wmtss1); - super.testQueryFilter(WMSStoreInfo.class, ecql, wmss1); - super.testQueryFilter(DataStoreInfo.class, ecql, ds1); - - ecql = String.format("\"workspace.id\" = '%s'", testData.workspaceB.getId()); - super.testQueryFilter(ecql, ds2); - } - - @Test void testDataStoreInfo_CRUD() throws IOException { - DataStoreInfo store = - testData.faker().dataStoreInfo( - "dataStoreCRUD-id", - testData.workspaceB, - "dataStoreCRUD", - "dataStoreCRUD description", - true); - crudTest( - store, - serverCatalog::getDataStore, - created -> { - created.setEnabled(false); - created.setName("modified name"); - created.setDescription("modified description"); - created.getConnectionParameters().put("newkey", "new param"); - return; - }, - (orig, updated) -> { - assertFalse(updated.isEnabled()); - assertEquals("modified name", updated.getName()); - assertEquals("modified description", updated.getDescription()); - assertEquals("new param", updated.getConnectionParameters().get("newkey")); - }); - } - - @Test void testCoverageStoreInfo_CRUD() { - CoverageStoreInfo store = - testData.createCoverageStore( - "coverageStoreCRUD", - testData.workspaceC, - "coverageStoreCRUD name", - "GeoTIFF", - "file:/test/coverageStoreCRUD.tiff"); - crudTest( - store, - serverCatalog::getCoverageStore, - created -> { - created.setEnabled(false); - created.setName("modified name"); - created.setDescription("modified description"); - ((CoverageStoreInfo) created) - .setURL("file:/test/coverageStoreCRUD_modified.tiff"); - return; - }, - (orig, updated) -> { - assertFalse(updated.isEnabled()); - assertEquals("modified name", updated.getName()); - assertEquals("modified description", updated.getDescription()); - assertEquals( - "file:/test/coverageStoreCRUD_modified.tiff", - ((CoverageStoreInfo) updated).getURL()); - }); - } - - @Test void testWMSStoreInfo_CRUD() { - WMSStoreInfo store = - testData.createWebMapServer( - "wmsStoreCRUD", - testData.workspaceA, - "wmsStoreCRUD_name", - "http://test.com", - true); - crudTest( - store, - id -> serverCatalog.getStore(id, WMSStoreInfo.class), - created -> { - created.setEnabled(false); - created.setName("modified name"); - created.setDescription("modified description"); - ((WMSStoreInfo) created).setCapabilitiesURL("http://new.caps.url"); - return; - }, - (orig, updated) -> { - assertFalse(updated.isEnabled()); - assertEquals("modified name", updated.getName()); - assertEquals("modified description", updated.getDescription()); - assertEquals( - "http://new.caps.url", ((WMSStoreInfo) updated).getCapabilitiesURL()); - }); - } - - @Test void testWMTSStoreInfo_CRUD() { - WMTSStoreInfo store = - testData.createWebMapTileServer( - "wmsStoreCRUD", - testData.workspaceA, - "wmtsStoreCRUD_name", - "http://test.com", - true); - crudTest( - store, - id -> serverCatalog.getStore(id, WMTSStoreInfo.class), - created -> { - created.setEnabled(false); - created.setName("modified name"); - created.setDescription("modified description"); - ((WMTSStoreInfo) created).setCapabilitiesURL("http://new.caps.url"); - return; - }, - (orig, updated) -> { - assertFalse(updated.isEnabled()); - assertEquals("modified name", updated.getName()); - assertEquals("modified description", updated.getDescription()); - assertEquals( - "http://new.caps.url", ((WMTSStoreInfo) updated).getCapabilitiesURL()); - }); - } - - @Test void testFindStoreById() throws IOException { - testFindById(testData.coverageStoreA); - testFindById(testData.dataStoreA); - testFindById(testData.dataStoreB); - testFindById(testData.wmsStoreA); - testFindById(testData.wmtsStoreA); - } - - @Test void testFindStoreById_SubtypeMismatch() throws IOException { - StoreRepository client = repository(); - assertTrue(client.findById(testData.coverageStoreA.getId(), DataStoreInfo.class).isEmpty()); - assertTrue(client.findById(testData.dataStoreA.getId(), CoverageStoreInfo.class).isEmpty()); - assertTrue(client.findById(testData.dataStoreB.getId(), CoverageStoreInfo.class).isEmpty()); - } - - @Test void testFindStoreByName() throws IOException { - findStoreByName(testData.coverageStoreA); - findStoreByName(testData.dataStoreA); - findStoreByName(testData.dataStoreB); - findStoreByName(testData.wmsStoreA); - findStoreByName(testData.wmtsStoreA); - } - - private void findStoreByName(StoreInfo store) { - StoreInfo responseBody = repository.findFirstByName(store.getName(), StoreInfo.class).get(); - StoreInfo resolved = resolveProxies(responseBody); - assertCatalogInfoEquals(store, resolved); - } - - @Test void testFindStoreByWorkspaceAndName() throws IOException { - testFindStoreByWorkspaceAndName(testData.coverageStoreA, StoreInfo.class); - testFindStoreByWorkspaceAndName(testData.coverageStoreA, CoverageStoreInfo.class); - - testFindStoreByWorkspaceAndName(testData.dataStoreA, StoreInfo.class); - testFindStoreByWorkspaceAndName(testData.dataStoreA, DataStoreInfo.class); - - testFindStoreByWorkspaceAndName(testData.dataStoreB, StoreInfo.class); - testFindStoreByWorkspaceAndName(testData.dataStoreB, DataStoreInfo.class); - - testFindStoreByWorkspaceAndName(testData.wmsStoreA, StoreInfo.class); - testFindStoreByWorkspaceAndName(testData.wmsStoreA, WMSStoreInfo.class); - - testFindStoreByWorkspaceAndName(testData.wmtsStoreA, StoreInfo.class); - testFindStoreByWorkspaceAndName(testData.wmtsStoreA, WMTSStoreInfo.class); - } - - private void testFindStoreByWorkspaceAndName(StoreInfo store, Class type) { - WorkspaceInfo workspace = store.getWorkspace(); - String name = store.getName(); - - StoreInfo found = repository().findByNameAndWorkspace(name, workspace, type).get(); - assertNotNull(found); - assertEquals(store.getId(), found.getId()); - assertEquals(store.getName(), found.getName()); - } - - @Test void testFindStoreByName_WrongWorkspace() throws IOException { - testFindStoreByName_WrongWorkspace(testData.coverageStoreA, testData.workspaceC); - testFindStoreByName_WrongWorkspace(testData.dataStoreA, testData.workspaceC); - testFindStoreByName_WrongWorkspace(testData.dataStoreB, testData.workspaceC); - testFindStoreByName_WrongWorkspace(testData.wmsStoreA, testData.workspaceC); - testFindStoreByName_WrongWorkspace(testData.wmtsStoreA, testData.workspaceC); - } - - private void testFindStoreByName_WrongWorkspace(StoreInfo store, WorkspaceInfo workspace) { - String name = store.getName(); - assertTrue(repository().findByNameAndWorkspace(name, workspace, StoreInfo.class).isEmpty()); - } - - @Test void testFindStoresByWorkspace() { - testFindStoresByWorkspace( - testData.workspaceA, - testData.dataStoreA, - testData.coverageStoreA, - testData.wmsStoreA, - testData.wmtsStoreA); - testFindStoresByWorkspace(testData.workspaceB, testData.dataStoreB); - WorkspaceInfo emptyWs = testData.faker().workspaceInfo("emptyws"); - NamespaceInfo emptyNs = testData.faker().namespace(); - serverCatalog.add(emptyWs); - serverCatalog.add(emptyNs); - testFindStoresByWorkspace(emptyWs); - } - - public void testFindStoresByWorkspace(WorkspaceInfo ws, StoreInfo... expected) { - Stream stores = repository().findAllByWorkspace(ws, StoreInfo.class); - Set expectedIds = - Arrays.stream(expected).map(StoreInfo::getId).collect(Collectors.toSet()); - Set actual = stores.map(StoreInfo::getId).collect(Collectors.toSet()); - - assertEquals(expectedIds, actual); - } -} diff --git a/src/integration-tests/catalog-service-it/src/test/java/org/geoserver/cloud/catalog/client/reactivefeign/StyleRepositoryTest.java b/src/integration-tests/catalog-service-it/src/test/java/org/geoserver/cloud/catalog/client/reactivefeign/StyleRepositoryTest.java deleted file mode 100644 index 38fb4e69a..000000000 --- a/src/integration-tests/catalog-service-it/src/test/java/org/geoserver/cloud/catalog/client/reactivefeign/StyleRepositoryTest.java +++ /dev/null @@ -1,217 +0,0 @@ -/* - * (c) 2020 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.cloud.catalog.client.reactivefeign; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertTrue; -import org.geoserver.catalog.LegendInfo; -import org.geoserver.catalog.SLDHandler; -import org.geoserver.catalog.StyleInfo; -import org.geoserver.catalog.WorkspaceInfo; -import org.geoserver.catalog.impl.LegendInfoImpl; -import org.geoserver.catalog.impl.StyleInfoImpl; -import org.geoserver.catalog.plugin.CatalogInfoRepository.StyleRepository; -import org.junit.jupiter.api.Test; -import org.geotools.api.filter.Filter; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.autoconfigure.EnableAutoConfiguration; -import lombok.Getter; -import lombok.experimental.Accessors; - -@EnableAutoConfiguration -@Accessors(fluent = true) -class StyleRepositoryTest - extends AbstractCatalogServiceClientRepositoryTest { - - private @Autowired @Getter StyleRepository repository; - - public StyleRepositoryTest() { - super(StyleInfo.class); - } - - protected @Override void assertPropertriesEqual(StyleInfo expected, StyleInfo actual) { - assertEquals(expected.getName(), actual.getName()); - assertEquals(expected.getFilename(), actual.getFilename()); - assertEquals(expected.getFormat(), actual.getFormat()); - assertEquals(expected.getFormatVersion(), actual.getFormatVersion()); - assertEquals(expected.getWorkspace(), actual.getWorkspace()); - assertLegendEquals(expected.getLegend(), actual.getLegend()); - } - - private void assertLegendEquals(LegendInfo expected, LegendInfo actual) { - if (expected == null || actual == null) assertEquals(expected, actual); - else { - assertEquals(expected.getFormat(), actual.getFormat()); - assertEquals(expected.getHeight(), actual.getHeight()); - assertEquals(expected.getOnlineResource(), actual.getOnlineResource()); - assertEquals(expected.getWidth(), actual.getWidth()); - } - } - - @Test void testStyleCRUD_NoWorkspace() { - StyleInfo style = testData.createStyle("styleCRUD", null, "styleCRUD", "styleCRUD.sld"); - ((StyleInfoImpl) style).setFormat(SLDHandler.FORMAT); - ((StyleInfoImpl) style).setFormatVersion(SLDHandler.VERSION_10); - crudTest( - style, - serverCatalog::getStyle, - created -> { - created.setName(created.getName() + "_modified"); - // this will be assigned by the catalog as the new file name when it renames the - // style, - // so change it here too for the equals check to pass - created.setFilename(created.getName() + ".sld"); - created.setFormat(SLDHandler.FORMAT); - created.setFormatVersion(SLDHandler.VERSION_11); - LegendInfoImpl legend = new LegendInfoImpl(); - legend.setFormat("test"); - legend.setHeight(10); - legend.setWidth(20); - legend.setOnlineResource("http://test.com/style.png"); - created.setLegend(legend); - }, - (orig, updated) -> { - assertEquals(orig.getName() + "_modified", updated.getName()); - assertEquals(updated.getName() + ".sld", updated.getFilename()); - assertEquals(SLDHandler.FORMAT, updated.getFormat()); - assertEquals(SLDHandler.VERSION_11, updated.getFormatVersion()); - assertEquals("test", updated.getLegend().getFormat()); - assertEquals(10, updated.getLegend().getHeight()); - assertEquals(20, updated.getLegend().getWidth()); - assertEquals( - "http://test.com/style.png", updated.getLegend().getOnlineResource()); - }); - } - - @Test void testStyleCRUD_Workspace() { - StyleInfo style = - testData.createStyle( - "styleCRUD_Workspace", - testData.workspaceB, - "styleCRUD_Workspace", - "styleCRUD_Workspace.sld"); - - style.setFormat(SLDHandler.FORMAT); - style.setFormatVersion(SLDHandler.VERSION_10); - - crudTest( - style, - serverCatalog::getStyle, - created -> { - created.setWorkspace(testData.workspaceC); - created.setFormatVersion(SLDHandler.VERSION_11); - }, - (orig, updated) -> { - assertEquals(testData.workspaceC, updated.getWorkspace()); - assertEquals(SLDHandler.VERSION_11, updated.getFormatVersion()); - }); - } - - public @Test @Override void testFindById() { - testFindById(testData.style1); - testFindById(testData.style2); - } - - public @Test @Override void testFindAll() { - testFindAll(testData.style1, testData.style2); - - WorkspaceInfo ws1 = testData.workspaceA; - WorkspaceInfo ws2 = testData.workspaceB; - StyleInfo ws1s1 = testData.createStyle("s1ws1", ws1); - StyleInfo ws2s1 = testData.createStyle("s1ws2", ws2); - serverCatalog.add(ws1s1); - serverCatalog.add(ws2s1); - - testFindAll(testData.style1, testData.style2, ws1s1, ws2s1); - } - - public @Test @Override void testFindAllByType() { - testFindAll(testData.style1, testData.style2); - } - - public @Test @Override void testQueryFilter() { - WorkspaceInfo ws1 = testData.workspaceA; - WorkspaceInfo ws2 = testData.workspaceB; - - StyleInfo ws1s1 = testData.createStyle("s1ws1", ws1); - StyleInfo ws1s2 = testData.createStyle("s2ws1", ws1); - StyleInfo ws2s1 = testData.createStyle("s1ws2", ws2); - StyleInfo ws2s2 = testData.createStyle("s2ws2", ws2); - serverCatalog.add(ws1s1); - serverCatalog.add(ws1s2); - serverCatalog.add(ws2s1); - serverCatalog.add(ws2s2); - - super.testQueryFilter( - StyleInfo.class, - Filter.INCLUDE, - testData.style1, - testData.style2, - ws1s1, - ws1s2, - ws2s1, - ws2s2); - String cql = "name like '%ws1'"; - super.testQueryFilter(cql, ws1s1, ws1s2); - } - - @Test void testFindStyleByNameAndNullWorkspace() { - WorkspaceInfo ws1 = testData.workspaceA; - StyleInfo ws1s1 = testData.createStyle("s1ws1", ws1); - serverCatalog.add(ws1s1); - - StyleInfo s1 = testData.style1; - StyleInfo s2 = testData.style2; - assertEquals( - s1.getId(), repository.findByNameAndWordkspaceNull(s1.getName()).get().getId()); - assertEquals( - s2.getId(), repository.findByNameAndWordkspaceNull(s2.getName()).get().getId()); - assertTrue(repository.findByNameAndWordkspaceNull(ws1s1.getName()).isEmpty()); - } - - @Test void testfindStyleByWorkspaceIdAndName() { - WorkspaceInfo ws1 = testData.workspaceA; - WorkspaceInfo ws2 = testData.workspaceB; - StyleInfo ws1s1 = testData.createStyle("s1ws1", ws1); - StyleInfo ws2s1 = testData.createStyle("s1ws2", ws2); - serverCatalog.add(ws1s1); - serverCatalog.add(ws2s1); - - assertEquals( - ws1s1.getId(), - repository.findByNameAndWorkspace(ws1s1.getName(), ws1).get().getId()); - assertEquals( - ws2s1.getId(), - repository.findByNameAndWorkspace(ws2s1.getName(), ws2).get().getId()); - - assertTrue(repository.findByNameAndWorkspace(ws1s1.getName(), ws2).isEmpty()); - assertTrue(repository.findByNameAndWorkspace(ws2s1.getName(), ws1).isEmpty()); - } - - @Test void testFindStylesByNullWorkspace() { - StyleInfo ws1s1 = testData.createStyle("s1ws1", testData.workspaceA); - serverCatalog.add(ws1s1); - - testFind(() -> repository.findAllByNullWorkspace(), testData.style1, testData.style2); - } - - @Test void testFindStylesByWorkspaceId() { - WorkspaceInfo ws1 = testData.workspaceA; - WorkspaceInfo ws2 = testData.workspaceB; - - StyleInfo ws1s1 = testData.createStyle("s1ws1", ws1); - StyleInfo ws1s2 = testData.createStyle("s2ws1", ws1); - StyleInfo ws2s1 = testData.createStyle("s1ws2", ws2); - StyleInfo ws2s2 = testData.createStyle("s2ws2", ws2); - serverCatalog.add(ws1s1); - serverCatalog.add(ws1s2); - serverCatalog.add(ws2s1); - serverCatalog.add(ws2s2); - - testFind(() -> repository.findAllByWorkspace(ws1), ws1s1, ws1s2); - testFind(() -> repository.findAllByWorkspace(ws2), ws2s1, ws2s2); - testFind(() -> repository.findAllByWorkspace(testData.workspaceC)); - } -} diff --git a/src/integration-tests/catalog-service-it/src/test/java/org/geoserver/cloud/catalog/client/reactivefeign/WorkspaceRepositoryTest.java b/src/integration-tests/catalog-service-it/src/test/java/org/geoserver/cloud/catalog/client/reactivefeign/WorkspaceRepositoryTest.java deleted file mode 100644 index 84ae992ef..000000000 --- a/src/integration-tests/catalog-service-it/src/test/java/org/geoserver/cloud/catalog/client/reactivefeign/WorkspaceRepositoryTest.java +++ /dev/null @@ -1,136 +0,0 @@ -/* - * (c) 2020 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.cloud.catalog.client.reactivefeign; - -import static java.lang.String.format; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertNotNull; -import static org.junit.jupiter.api.Assertions.assertNull; -import static org.junit.jupiter.api.Assertions.assertTrue; -import org.geoserver.catalog.WorkspaceInfo; -import org.geoserver.catalog.plugin.CatalogInfoRepository.WorkspaceRepository; -import org.junit.jupiter.api.Test; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.autoconfigure.EnableAutoConfiguration; -import lombok.Getter; -import lombok.experimental.Accessors; - -@EnableAutoConfiguration -@Accessors(fluent = true) -class WorkspaceRepositoryTest - extends AbstractCatalogServiceClientRepositoryTest { - - private @Autowired @Getter WorkspaceRepository repository; - - public WorkspaceRepositoryTest() { - super(WorkspaceInfo.class); - } - - protected @Override void assertPropertriesEqual(WorkspaceInfo expected, WorkspaceInfo actual) { - assertEquals(expected.getName(), actual.getName()); - assertEquals(expected.isIsolated(), actual.isIsolated()); - } - - @Override public @Test void testFindById() { - testFindById(testData.workspaceA); - testFindById(testData.workspaceB); - testFindById(testData.workspaceC); - } - - @Override public @Test void testFindAll() { - super.testFindAll(testData.workspaceA, testData.workspaceB, testData.workspaceC); - } - - @Override public @Test void testFindAllByType() { - super.testFindAllIncludeFilter( - WorkspaceInfo.class, testData.workspaceA, testData.workspaceB, testData.workspaceC); - } - - @Override public @Test void testQueryFilter() { - WorkspaceInfo wsA = serverCatalog.getWorkspace(testData.workspaceA.getId()); - WorkspaceInfo wsB = serverCatalog.getWorkspace(testData.workspaceB.getId()); - WorkspaceInfo wsC = serverCatalog.getWorkspace(testData.workspaceC.getId()); - - wsB.setIsolated(true); - wsC.setIsolated(true); - serverCatalog.save(wsB); - serverCatalog.save(wsC); - - super.testQueryFilter("isolated = true", wsB, wsC); - super.testQueryFilter("isolated = false", wsA); - super.testQueryFilter(format("\"id\" = '%s'", wsA.getId()), wsA); - } - - @Test void testFindByName() { - WorkspaceInfo ws1 = testData.workspaceA; - assertEquals(ws1, repository.findFirstByName(ws1.getName(), infoType).get()); - } - - @Test void testWorkspaceCRUD() { - WorkspaceInfo ws = testData.faker().workspaceInfo("workspaceCRUD"); - crudTest( - ws, - serverCatalog::getWorkspace, - w -> { - w.setName("modified_name"); - w.setIsolated(true); - }, - (orig, updated) -> { - assertEquals("modified_name", updated.getName()); - assertTrue(updated.isIsolated()); - }); - } - - @Test void testGetDefaultWorkspace() { - WorkspaceInfo expected = serverCatalog.getDefaultWorkspace(); - assertNotNull(expected); - WorkspaceInfo actual = repository.getDefaultWorkspace().get(); - assertEquals(expected, actual); - } - - @Test void testGetDefaultWorkspaceIsNullOnEmptyCatalog() { - testData.deleteAll(); - assertNull(serverCatalog.getDefaultWorkspace()); - assertFalse(repository.getDefaultWorkspace().isPresent()); - } - - @Test void testSetDefaultWorkspace() { - WorkspaceInfo current = serverCatalog.getDefaultWorkspace(); - assertNotNull(current); - assertEquals(testData.workspaceA.getId(), current.getId()); - assertEquals(testData.workspaceA, repository.getDefaultWorkspace().get()); - - WorkspaceInfo expected = testData.workspaceB; - - repository.setDefaultWorkspace(expected); - assertEquals(expected, serverCatalog.getDefaultWorkspace()); - assertEquals(expected, repository.getDefaultWorkspace().get()); - } - - @Test void testUnsetDefaultWorkspace() { - WorkspaceInfo ws2 = testData.workspaceB; - // preflight check - serverCatalog.setDefaultWorkspace(null); - assertNull(serverCatalog.getDefaultWorkspace()); - serverCatalog.setDefaultWorkspace(ws2); - assertEquals(ws2, serverCatalog.getDefaultWorkspace()); - - WorkspaceInfo current = serverCatalog.getDefaultWorkspace(); - assertNotNull(current); - assertEquals(ws2.getId(), current.getId()); - - repository.unsetDefaultWorkspace(); - - assertNull(serverCatalog.getDefaultWorkspace()); - assertTrue(repository.getDefaultWorkspace().isEmpty()); - - // check idempotency - repository.unsetDefaultWorkspace(); - - assertNull(serverCatalog.getDefaultWorkspace()); - assertTrue(repository.getDefaultWorkspace().isEmpty()); - } -} diff --git a/src/integration-tests/catalog-service-it/src/test/java/org/geoserver/cloud/integration/catalog/AbstractCatalogBackendIT.java b/src/integration-tests/catalog-service-it/src/test/java/org/geoserver/cloud/integration/catalog/AbstractCatalogBackendIT.java deleted file mode 100644 index c7909256c..000000000 --- a/src/integration-tests/catalog-service-it/src/test/java/org/geoserver/cloud/integration/catalog/AbstractCatalogBackendIT.java +++ /dev/null @@ -1,112 +0,0 @@ -/* - * (c) 2020 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.cloud.integration.catalog; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertNotNull; -import java.io.IOException; -import java.util.List; -import org.geoserver.catalog.Catalog; -import org.geoserver.catalog.LayerInfo; -import org.geoserver.catalog.NamespaceInfo; -import org.geoserver.catalog.WMTSLayerInfo; -import org.geoserver.catalog.WMTSStoreInfo; -import org.geoserver.catalog.WorkspaceInfo; -import org.geoserver.catalog.plugin.CatalogConformanceTest; -import org.geotools.ows.wmts.WebMapTileServer; -import org.geotools.ows.wmts.model.WMTSCapabilities; -import org.geotools.ows.wmts.model.WMTSLayer; -import org.junit.jupiter.api.Test; -import org.geotools.api.util.ProgressListener; - -public abstract class AbstractCatalogBackendIT extends CatalogConformanceTest { - - final String LIVE_WMTS_GETCAPS_URL = - "https://wmts.geo.admin.ch/EPSG/3857/1.0.0/WMTSCapabilities.xml"; - - @Test - void onlineWMTS_addStore() throws IOException { - final WorkspaceInfo ws = addWorkspace(); - WMTSStoreInfo store = addWMTSStore(ws, LIVE_WMTS_GETCAPS_URL); - assertNotNull(store); - WebMapTileServer wmts = store.getWebMapTileServer((ProgressListener) null); - assertNotNull(wmts); - WMTSCapabilities capabilities = wmts.getCapabilities(); - assertNotNull(capabilities); - List layers = capabilities.getLayerList(); - assertNotNull(layers); - assertFalse(layers.isEmpty()); - } - - @Test - void onlineWMTS_addResource() throws IOException { - final WorkspaceInfo ws = addWorkspace(); - final NamespaceInfo ns = addNamespace(); - final WMTSStoreInfo store = addWMTSStore(ws, LIVE_WMTS_GETCAPS_URL); - final WebMapTileServer wmts = store.getWebMapTileServer((ProgressListener) null); - final WMTSCapabilities capabilities = wmts.getCapabilities(); - final List layers = capabilities.getLayerList(); - final WMTSLayer wmtsLayer = layers.get(0); - - final String layerName = wmtsLayer.getName(); - final WMTSLayerInfo resource = addWMTSLayer(ns, store, layerName); - assertNotNull(resource); - assertNotNull(resource.getCatalog()); - assertEquals(ns, resource.getNamespace()); - assertEquals(layerName, resource.getName()); - assertEquals(layerName, resource.getNativeName()); - - final Catalog catalog = super.catalog; - WMTSLayerInfo resourceByName = - catalog.getResourceByName(ns, layerName, WMTSLayerInfo.class); - assertEquals(resource, resourceByName); - WMTSLayerInfo resourceByStore = - catalog.getResourceByStore(store, layerName, WMTSLayerInfo.class); - assertEquals(resource, resourceByStore); - } - - @Test - void onlineWMTS_addLayer() throws IOException { - final WorkspaceInfo ws = addWorkspace(); - final NamespaceInfo ns = addNamespace(); - final WMTSStoreInfo store = addWMTSStore(ws, LIVE_WMTS_GETCAPS_URL); - final WebMapTileServer wmts = store.getWebMapTileServer((ProgressListener) null); - final WMTSCapabilities capabilities = wmts.getCapabilities(); - final List layers = capabilities.getLayerList(); - final WMTSLayer wmtsLayer = layers.get(0); - - final String layerName = wmtsLayer.getName(); - final WMTSLayerInfo resource = addWMTSLayer(ns, store, layerName); - - final Catalog catalog = super.catalog; - LayerInfo layer = catalog.getFactory().createLayer(); - layer.setResource(resource); - layer.setName(layerName); - - LayerInfo layerInfo = add(layer, catalog::add, catalog::getLayer); - assertNotNull(layerInfo); - assertEquals(resource, layerInfo.getResource()); - } - - protected WMTSStoreInfo addWMTSStore(WorkspaceInfo workspace, String getCapsUrl) { - WMTSStoreInfo store = catalog.getFactory().createWebMapTileServer(); - store.setWorkspace(workspace); - store.setName("wmtsstore"); - store.setCapabilitiesURL(getCapsUrl); - store.setUseConnectionPooling(true); - return add(store, catalog::add, id -> catalog.getStore(id, WMTSStoreInfo.class)); - } - - protected WMTSLayerInfo addWMTSLayer(NamespaceInfo ns, WMTSStoreInfo wmts, String layerName) { - WMTSLayerInfo resource = catalog.getFactory().createWMTSLayer(); - resource.setName(layerName); - resource.setStore(wmts); - resource.setNamespace(ns); - resource.setEnabled(true); - return add( - resource, catalog::add, id -> catalog.getResource(id, WMTSLayerInfo.class)); - } -} diff --git a/src/integration-tests/catalog-service-it/src/test/java/org/geoserver/cloud/integration/catalog/IntegrationTestConfiguration.java b/src/integration-tests/catalog-service-it/src/test/java/org/geoserver/cloud/integration/catalog/IntegrationTestConfiguration.java deleted file mode 100644 index 1f22a3edf..000000000 --- a/src/integration-tests/catalog-service-it/src/test/java/org/geoserver/cloud/integration/catalog/IntegrationTestConfiguration.java +++ /dev/null @@ -1,24 +0,0 @@ -/* - * (c) 2020 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.cloud.integration.catalog; - -import org.springframework.boot.actuate.autoconfigure.security.servlet.ManagementWebSecurityAutoConfiguration; -import org.springframework.boot.autoconfigure.EnableAutoConfiguration; -import org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration; -import org.springframework.boot.autoconfigure.security.servlet.UserDetailsServiceAutoConfiguration; -import org.springframework.context.annotation.Configuration; - -/** - * Simple configuration to be referred to by integration tests that relied on auto-configuration to - * set up the context - */ -@Configuration -@EnableAutoConfiguration( - exclude = { - SecurityAutoConfiguration.class, - UserDetailsServiceAutoConfiguration.class, - ManagementWebSecurityAutoConfiguration.class - }) -public class IntegrationTestConfiguration {} diff --git a/src/integration-tests/catalog-service-it/src/test/java/org/geoserver/cloud/integration/catalogservice/CatalogClientBackendIntegrationTest.java b/src/integration-tests/catalog-service-it/src/test/java/org/geoserver/cloud/integration/catalogservice/CatalogClientBackendIntegrationTest.java deleted file mode 100644 index 544417a8a..000000000 --- a/src/integration-tests/catalog-service-it/src/test/java/org/geoserver/cloud/integration/catalogservice/CatalogClientBackendIntegrationTest.java +++ /dev/null @@ -1,112 +0,0 @@ -/* - * (c) 2020 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.cloud.integration.catalogservice; - -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.greaterThan; -import static org.junit.jupiter.api.Assertions.*; - -import com.google.common.collect.Lists; - -import org.geoserver.catalog.Catalog; -import org.geoserver.catalog.CatalogFacade; -import org.geoserver.catalog.CoverageStoreInfo; -import org.geoserver.catalog.DataStoreInfo; -import org.geoserver.catalog.Predicates; -import org.geoserver.catalog.StoreInfo; -import org.geoserver.catalog.WMSStoreInfo; -import org.geoserver.catalog.WMTSStoreInfo; -import org.geoserver.catalog.plugin.CatalogInfoRepository; -import org.geoserver.catalog.plugin.CatalogPlugin; -import org.geoserver.cloud.catalog.app.CatalogServiceApplication; -import org.geoserver.cloud.catalog.client.impl.CatalogClientConfiguration; -import org.geoserver.cloud.catalog.client.repository.CatalogClientRepository; -import org.geoserver.cloud.integration.catalog.AbstractCatalogBackendIT; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.geotools.api.filter.Filter; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Qualifier; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.boot.test.context.SpringBootTest.WebEnvironment; -import org.springframework.test.context.ActiveProfiles; - -import java.util.ArrayList; - -/** - * {@link Catalog} integration and conformance tests for a {@link CatalogFacade} running off - * catalog-service's client {@link CatalogClientRepository repositories} hitting a real back-end - * catalog-service. - * - *

A {@link Catalog} using the {@code catalog-service} as its back-end is a regular {@link - * CatalogPlugin} with an injected {@link CatalogFacade} whose {@link CatalogInfoRepository - * repositories} talk to the {@code catalog-service}, hence this integration test suite verifies the - * functioning of such {@code CatalogFacade} against a live {@code catalog-service} instance through - * HTTP. - */ -@SpringBootTest( - classes = { // - CatalogServiceApplication.class, // - CatalogClientConfiguration.class // - }, - webEnvironment = WebEnvironment.DEFINED_PORT, - properties = { - "spring.cloud.circuitbreaker.hystrix.enabled=false", - "spring.main.web-application-type=reactive", - "server.port=16666", - "geoserver.backend.catalog-service.uri=http://localhost:${server.port}" - }) -@ActiveProfiles("it.catalog-service") -// REVISIT: fails if run with failsafe "ClassNotFoundException: -// org.geoserver.cloud.catalog.client.reactivefeign.ReactiveCatalogClient" -class CatalogClientBackendIntegrationTest extends AbstractCatalogBackendIT { - /** - * WebFlux catalog-service catalog with backend as configured by - * bootstrap-it.catalog-service.yml - */ - private @Autowired @Qualifier("catalog") Catalog serverCatalog; - - private @Autowired @Qualifier("rawCatalogServiceFacade") CatalogFacade clientFacade; - - /** Client catalog through which to hit the server catalog */ - private CatalogPlugin clientCatalog; - - protected @Override CatalogPlugin createCatalog() { - clientCatalog = new CatalogPlugin(clientFacade); - return clientCatalog; - } - - public @BeforeEach void purgeServerCatalog() { - serverCatalog.removeListeners(TestListener.class); - serverCatalog.removeListeners(ExceptionThrowingListener.class); - super.data.deleteAll(serverCatalog); - } - - @Test void testQueryFilterInstanceOf() { - super.data.addObjects(); - int expected = serverCatalog.getDataStores().size(); - assertThat(expected, greaterThan(0)); - - Filter filter = Predicates.isInstanceOf(DataStoreInfo.class); - ArrayList list = Lists.newArrayList(catalog.list(StoreInfo.class, filter)); - assertEquals(3, list.size()); - - filter = Predicates.isInstanceOf(CoverageStoreInfo.class); - list = Lists.newArrayList(catalog.list(StoreInfo.class, filter)); - assertEquals(1, list.size()); - - filter = Predicates.isInstanceOf(WMSStoreInfo.class); - list = Lists.newArrayList(catalog.list(StoreInfo.class, filter)); - assertEquals(1, list.size()); - - filter = Predicates.isInstanceOf(WMTSStoreInfo.class); - list = Lists.newArrayList(catalog.list(StoreInfo.class, filter)); - assertEquals(1, list.size()); - - filter = Predicates.isInstanceOf(StoreInfo.class); - list = Lists.newArrayList(catalog.list(StoreInfo.class, filter)); - assertEquals(6, list.size()); - } -} diff --git a/src/integration-tests/catalog-service-it/src/test/java/org/geoserver/cloud/integration/catalogservice/CatalogClientGeoServerFacadeConformanceTest.java b/src/integration-tests/catalog-service-it/src/test/java/org/geoserver/cloud/integration/catalogservice/CatalogClientGeoServerFacadeConformanceTest.java deleted file mode 100644 index 54a22178a..000000000 --- a/src/integration-tests/catalog-service-it/src/test/java/org/geoserver/cloud/integration/catalogservice/CatalogClientGeoServerFacadeConformanceTest.java +++ /dev/null @@ -1,96 +0,0 @@ -/* - * (c) 2020 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.cloud.integration.catalogservice; - -import org.geoserver.catalog.Catalog; -import org.geoserver.catalog.CatalogFacade; -import org.geoserver.catalog.CatalogTestData; -import org.geoserver.catalog.plugin.CatalogPlugin; -import org.geoserver.cloud.catalog.app.CatalogServiceApplication; -import org.geoserver.cloud.catalog.client.impl.CatalogClientConfiguration; -import org.geoserver.cloud.catalog.client.impl.CatalogClientGeoServerFacade; -import org.geoserver.cloud.catalog.client.reactivefeign.ReactiveConfigClient; -import org.geoserver.cloud.catalog.client.repository.CatalogClientConfigRepository; -import org.geoserver.config.GeoServer; -import org.geoserver.config.GeoServerConfigConformanceTest; -import org.geoserver.config.ServiceInfo; -import org.geoserver.config.plugin.GeoServerImpl; -import org.geoserver.wms.WMSInfoImpl; -import org.junit.jupiter.api.AfterEach; -import org.junit.jupiter.api.Assumptions; -import org.junit.jupiter.api.Test; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Qualifier; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.boot.test.context.SpringBootTest.WebEnvironment; -import org.springframework.test.context.ActiveProfiles; - -/** - * API {@link GeoServerConfigConformanceTest conformance test} for a {@link GeoServer} configuration - * manager backed by a {@link CatalogClientGeoServerFacade} (which in turn is backed by a {@link - * CatalogClientConfigRepository}), which in turn is backed by a {@link ReactiveConfigClient}, - * hitting a live {@code catalog-service} instance. - */ -@SpringBootTest( - classes = { // - CatalogServiceApplication.class, // - CatalogClientConfiguration.class // - }, - webEnvironment = WebEnvironment.DEFINED_PORT, - properties = { - "spring.cloud.circuitbreaker.hystrix.enabled=false", - "spring.main.web-application-type=reactive", - "server.port=15555", - "geoserver.backend.catalog-service.uri=http://localhost:${server.port}" - }) -@ActiveProfiles("it.catalog-service") -class CatalogClientGeoServerFacadeConformanceTest extends GeoServerConfigConformanceTest { - - /** - * WebFlux catalog-service catalog with backend as configured by - * bootstrap-it.catalog-service.yml - */ - private @Autowired @Qualifier("catalog") Catalog serverCatalog; - - private @Autowired @Qualifier("geoServer") GeoServer serverConfig; - - private @Autowired CatalogClientGeoServerFacade facade; - private @Autowired @Qualifier("rawCatalogServiceFacade") CatalogFacade clientFacade; - - protected @Override GeoServer createGeoServer() { - Catalog catalog = new CatalogPlugin(clientFacade); - - GeoServerImpl gs = new GeoServerImpl(); - gs.setCatalog(catalog); - gs.setFacade(facade); - return gs; - } - - protected @Override ServiceInfo createService() { - return new WMSInfoImpl(); - } - - /** prune the server catalog */ - @AfterEach - public void deleteAll() { - CatalogTestData.empty(() -> serverCatalog, () -> serverConfig).deleteAll(); - } - - /** - * Test works if run alone, but not if it runs after other tests cause server config is not null - */ - @Override public @Test void testGlobal() throws Exception { - Assumptions.assumeTrue(serverConfig.getGlobal() == null); - super.testGlobal(); - } - - /** - * Test works if run alone, but not if it runs after other tests cause server config is not null - */ - @Override public @Test void testModifyGlobal() throws Exception { - Assumptions.assumeTrue(serverConfig.getGlobal() == null); - super.testModifyGlobal(); - } -} diff --git a/src/integration-tests/catalog-service-it/src/test/java/org/geoserver/cloud/integration/datadirectory/DataDirectoryCatalogIT.java b/src/integration-tests/catalog-service-it/src/test/java/org/geoserver/cloud/integration/datadirectory/DataDirectoryCatalogIT.java deleted file mode 100644 index 80eaf5681..000000000 --- a/src/integration-tests/catalog-service-it/src/test/java/org/geoserver/cloud/integration/datadirectory/DataDirectoryCatalogIT.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * (c) 2020 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.cloud.integration.datadirectory; - -import org.geoserver.catalog.CatalogFacade; -import org.geoserver.catalog.plugin.CatalogPlugin; -import org.geoserver.cloud.integration.catalog.AbstractCatalogBackendIT; -import org.geoserver.cloud.integration.catalog.IntegrationTestConfiguration; -import org.geoserver.platform.GeoServerResourceLoader; -import org.junit.jupiter.api.AfterEach; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Qualifier; -import org.springframework.boot.test.context.SpringBootTest; - -@SpringBootTest(classes = IntegrationTestConfiguration.class, - properties = {"geoserver.backend.data-directory.enabled=true", - "spring.cloud.circuitbreaker.hystrix.enabled=false", - "spring.cloud.config.retry.max-attempts=1"}) -class DataDirectoryCatalogIT extends AbstractCatalogBackendIT { - - private @Autowired @Qualifier("catalogFacade") CatalogFacade rawCatalogFacade; - private @Autowired GeoServerResourceLoader resourceLoader; - - @Override - protected CatalogPlugin createCatalog() { - CatalogPlugin catalog = new CatalogPlugin(rawCatalogFacade); - catalog.setResourceLoader(resourceLoader); - return catalog; - } - - public @AfterEach void deleteAll() { - data.deleteAll(super.catalog); - } -} diff --git a/src/integration-tests/catalog-service-it/src/test/java/org/geoserver/cloud/integration/jdbcconfig/JDBCConfigCatalogConcurrencyIT.java b/src/integration-tests/catalog-service-it/src/test/java/org/geoserver/cloud/integration/jdbcconfig/JDBCConfigCatalogConcurrencyIT.java deleted file mode 100644 index 91d1559ae..000000000 --- a/src/integration-tests/catalog-service-it/src/test/java/org/geoserver/cloud/integration/jdbcconfig/JDBCConfigCatalogConcurrencyIT.java +++ /dev/null @@ -1,152 +0,0 @@ -/* - * (c) 2020 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.cloud.integration.jdbcconfig; - -import static org.junit.jupiter.api.Assertions.assertNotNull; -import java.util.Collection; -import java.util.concurrent.Callable; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.concurrent.ThreadFactory; -import java.util.concurrent.TimeUnit; -import java.util.stream.IntStream; -import org.geoserver.catalog.Catalog; -import org.geoserver.catalog.CatalogTestData; -import org.geoserver.catalog.CoverageInfo; -import org.geoserver.catalog.CoverageStoreInfo; -import org.geoserver.catalog.DataStoreInfo; -import org.geoserver.catalog.FeatureTypeInfo; -import org.geoserver.catalog.ResourceInfo; -import org.geoserver.catalog.StoreInfo; -import org.geoserver.catalog.WMSLayerInfo; -import org.geoserver.catalog.WMSStoreInfo; -import org.geoserver.catalog.WMTSLayerInfo; -import org.geoserver.catalog.WMTSStoreInfo; -import org.geoserver.catalog.plugin.ExtendedCatalogFacade; -import org.geoserver.cloud.integration.catalog.IntegrationTestConfiguration; -import org.geoserver.config.GeoServer; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Qualifier; -import org.springframework.boot.test.context.SpringBootTest; -import com.google.common.util.concurrent.ThreadFactoryBuilder; -import lombok.extern.slf4j.Slf4j; - -@SpringBootTest(classes = IntegrationTestConfiguration.class, properties = {// - "geoserver.backend.jdbcconfig.enabled=true"// - , "geoserver.backend.jdbcconfig.datasource.minimumIdle=1"// - , "geoserver.backend.jdbcconfig.datasource.maximumPoolSize=2"// - // 250ms is the minimum accepted by hikari - , "geoserver.backend.jdbcconfig.datasource.connectionTimeout=250"// - , "logging.level.org.geoserver.cloud.autoconfigure.bus=ERROR"// - , "logging.level.org.geoserver.cloud.integration.jdbcconfig=debug"// - , "logging.level.org.geoserver.jdbcconfig=info"// -}) -@Slf4j -class JDBCConfigCatalogConcurrencyIT { - - private @Autowired @Qualifier("catalogFacade") ExtendedCatalogFacade jdbcCatalogFacade; - private @Autowired @Qualifier("rawCatalog") Catalog rawCatalog; - private @Autowired GeoServer geoServer; - - private CatalogTestData data; - - - // public static @BeforeClass void oneTimeSetup() { - // GeoServerExtensionsHelper.setIsSpringContext(false); - // if (null == GeoServerExtensions.bean("sldHandler")) - // GeoServerExtensionsHelper.singleton("sldHandler", new SLDHandler(), StyleHandler.class); - // } - - @BeforeEach - public void setUp() throws Exception { - data = CatalogTestData.empty(() -> rawCatalog, () -> geoServer).initialize(); - data.deleteAll(); - } - - public @BeforeEach void prepare() { - data.deleteAll(rawCatalog); - jdbcCatalogFacade.dispose(); // disposes internal caches - } - - @Test void catalogConcurrency_1() { - data.addObjects(); - concurrencyTest(1); - } - - @Test void catalogConcurrency_4() { - data.addObjects(); - concurrencyTest(4); - } - - @Test void catalogConcurrency_16() { - data.addObjects(); - concurrencyTest(16); - } - - @Test void catalogConcurrency_32() { - data.addObjects(); - concurrencyTest(32); - } - - private void concurrencyTest(int threads) { - log.info("Running concurrency test with {} threads...", threads); - final int reps = 10; - Collection> tasks = IntStream.rangeClosed(1, threads)// - .mapToObj(i -> (Callable) () -> { - for(int rep = 0; rep < reps; rep++) - query(); - return null; - }).toList(); - - ThreadFactory threadFactory = new ThreadFactoryBuilder() - .setNameFormat("thread %d [0-" + (threads - 1) + "]").build(); - ExecutorService executor = Executors.newFixedThreadPool(threads, threadFactory); - try { - executor.invokeAll(tasks); - executor.shutdown(); - executor.awaitTermination(2, TimeUnit.MINUTES); - } catch (InterruptedException e) { - throw new RuntimeException(e); - } finally { - executor.shutdownNow(); - } - } - - private void query() { - //log.info("Querying catalog objects"); - assertNotNull(rawCatalog.getWorkspace(data.workspaceA.getId())); - assertNotNull(rawCatalog.getWorkspace(data.workspaceB.getId())); - assertNotNull(rawCatalog.getWorkspace(data.workspaceC.getId())); - - assertNotNull(rawCatalog.getStore(data.dataStoreA.getId(), DataStoreInfo.class)); - assertNotNull(rawCatalog.getStore(data.dataStoreB.getId(), DataStoreInfo.class)); - assertNotNull(rawCatalog.getStore(data.dataStoreC.getId(), DataStoreInfo.class)); - - assertNotNull(rawCatalog.getStore(data.coverageStoreA.getId(), CoverageStoreInfo.class)); - assertNotNull(rawCatalog.getStore(data.wmsStoreA.getId(), WMSStoreInfo.class)); - assertNotNull(rawCatalog.getStore(data.wmtsStoreA.getId(), WMTSStoreInfo.class)); - - assertNotNull(rawCatalog.getResource(data.featureTypeA.getId(), FeatureTypeInfo.class)); - assertNotNull(rawCatalog.getResource(data.coverageA.getId(), CoverageInfo.class)); - assertNotNull(rawCatalog.getResource(data.wmsLayerA.getId(), WMSLayerInfo.class)); - assertNotNull(rawCatalog.getResource(data.wmtsLayerA.getId(), WMTSLayerInfo.class)); - - assertNotNull(rawCatalog.getStyle(data.style1.getId())); - assertNotNull(rawCatalog.getStyle(data.style2.getId())); - assertNotNull(rawCatalog.getLayer(data.layerFeatureTypeA.getId())); - assertNotNull(rawCatalog.getLayerGroup(data.layerGroup1.getId())); - - rawCatalog.getNamespaces(); - rawCatalog.getWorkspaces(); - rawCatalog.getLayers(); - rawCatalog.getStores(StoreInfo.class); - rawCatalog.getResources(ResourceInfo.class); - rawCatalog.getStyles(); - } -} - - diff --git a/src/integration-tests/catalog-service-it/src/test/java/org/geoserver/cloud/integration/jdbcconfig/JDBCConfigCatalogIT.java b/src/integration-tests/catalog-service-it/src/test/java/org/geoserver/cloud/integration/jdbcconfig/JDBCConfigCatalogIT.java deleted file mode 100644 index 3df95ded6..000000000 --- a/src/integration-tests/catalog-service-it/src/test/java/org/geoserver/cloud/integration/jdbcconfig/JDBCConfigCatalogIT.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * (c) 2020 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.cloud.integration.jdbcconfig; - -import org.geoserver.catalog.plugin.CatalogPlugin; -import org.geoserver.catalog.plugin.ExtendedCatalogFacade; -import org.geoserver.cloud.integration.catalog.AbstractCatalogBackendIT; -import org.geoserver.cloud.integration.catalog.IntegrationTestConfiguration; -import org.geoserver.platform.GeoServerResourceLoader; -import org.junit.jupiter.api.BeforeEach; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Qualifier; -import org.springframework.boot.test.context.SpringBootTest; - -@SpringBootTest( - classes = IntegrationTestConfiguration.class, - properties = { - "geoserver.backend.jdbcconfig.enabled=true", - "logging.level.org.geoserver.cloud.autoconfigure.bus=ERROR" - }) -class JDBCConfigCatalogIT extends AbstractCatalogBackendIT { - - private @Autowired @Qualifier("catalogFacade") ExtendedCatalogFacade jdbcCatalogFacade; - private @Autowired GeoServerResourceLoader resourceLoader; - - @Override - protected CatalogPlugin createCatalog() { - CatalogPlugin catalog = new CatalogPlugin(jdbcCatalogFacade); - catalog.setResourceLoader(resourceLoader); - return catalog; - } - - public @BeforeEach void prepare() { - data.deleteAll(super.catalog); - jdbcCatalogFacade.dispose(); // disposes internal caches - } -} diff --git a/src/integration-tests/catalog-service-it/src/test/resources/application-it.catalog-service.yml b/src/integration-tests/catalog-service-it/src/test/resources/application-it.catalog-service.yml deleted file mode 100644 index 528b071b9..000000000 --- a/src/integration-tests/catalog-service-it/src/test/resources/application-it.catalog-service.yml +++ /dev/null @@ -1,60 +0,0 @@ -server.port: 15555 -geoserver: - # WebFlux catalog-service configuration - security.enabled: false - catalog: - isolated: false - # Disable advertised catalog, it checks the org.geoserver.ows.Dispatcher.REQUEST to check if an OWS is in progress, - # which can never be the case, and causes a java.lang.NoClassDefFoundError on org.springframework.web.servlet.mvc.AbstractController - advertised: false - # Disable LocalWorkspaceCatalog decorator, this service exposes a "raw catalog" backend, there's no concept of local workspaces - localWorkspace: false - secure: false - catalog-service: - io-threads: - max-size: 4 - max-queued: 10000 - backend.data-directory.enabled: true - backend.jdbcconfig.enabled: false - -# disable hyxtrix to allow debugging without timeouts -feign.hystrix.enabled: false - -# Feign debug levels: -# NONE, No logging (DEFAULT). -# BASIC, Log only the request method and URL and the response status code and execution time. -# HEADERS, Log the basic information along with request and response headers. -# FULL, Log the headers, body, and metadata for both requests and responses. -#feign.logger.level: full -#feign: -# client: -# config: -# catalog-service: -# connectTimeout: 500 -# readTimeout: 5000 -# loggerLevel: full - -spring: - jackson: - default-property-inclusion: non-empty - serialization: - indent-output: true - autoconfigure: - exclude: - - org.springframework.boot.autoconfigure.security.reactive.ReactiveSecurityAutoConfiguration - - org.springframework.boot.autoconfigure.security.reactive.ReactiveUserDetailsServiceAutoConfiguration - - org.springframework.boot.actuate.autoconfigure.security.reactive.ReactiveManagementWebSecurityAutoConfiguration - - -logging: - level: - root: warn - reactivefeign.client.log: info - org.geoserver.cloud: info - org.geoserver.jackson: info - org.geotools.jackson: info - org.geoserver.cloud.config.factory: info - org.geoserver.platform: warn - org.springframework.test: error - o.s.integration.handler.LoggingHandler: off - \ No newline at end of file diff --git a/src/integration-tests/catalog-service-it/src/test/resources/bootstrap.yml b/src/integration-tests/catalog-service-it/src/test/resources/bootstrap.yml deleted file mode 100644 index 999d20ebc..000000000 --- a/src/integration-tests/catalog-service-it/src/test/resources/bootstrap.yml +++ /dev/null @@ -1,43 +0,0 @@ -geoserver: - security.enabled: false - catalog: - isolated: true - advertised: true - localWorkspace: true - secure: true - catalog-service: - io-threads: - max-size: 4 - max-queued: 10000 - backend: - data-directory: - enabled: false - location: ${java.io.tmpdir}/gscloud_tests/data_directory_${random.uuid} - jdbcconfig: - enabled: false - initdb: true - cache-directory: ${java.io.tmpdir}/gscloud_tests/jdbcconfig_cache_${random.uuid} - datasource: - driverClassname: org.h2.Driver - url: jdbc:h2:mem:test;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE - username: sa - password: - -spring: - main: - banner-mode: off - allow-bean-definition-overriding: true - allow-circular-references: true # false by default since spring-boot 2.6.0, breaks geoserver initialization - cloud.config.enabled: false - cloud.config.discovery.enabled: false - cloud.bus.enabled: false -eureka.client.enabled: false - - -logging: - level: - root: WARN - org.geoserver.platform: error - org.geoserver.cloud: warn - org.geoserver.cloud.config.factory: info - org.springframework.test: error diff --git a/src/integration-tests/catalog-service-it/src/test/resources/logback-test.xml b/src/integration-tests/catalog-service-it/src/test/resources/logback-test.xml deleted file mode 100644 index 92a70edd5..000000000 --- a/src/integration-tests/catalog-service-it/src/test/resources/logback-test.xml +++ /dev/null @@ -1,15 +0,0 @@ - - - - %d{HH:mm:ss.SSS} [%thread] %-5level %logger - %msg%n - - - - - - - - - - - \ No newline at end of file diff --git a/src/integration-tests/pom.xml b/src/integration-tests/pom.xml index db5ebbcdc..75470d68d 100644 --- a/src/integration-tests/pom.xml +++ b/src/integration-tests/pom.xml @@ -9,10 +9,7 @@ integration-tests pom Integration Tests - - - - + org.springframework.boot diff --git a/src/pom.xml b/src/pom.xml index c3c44a697..6eef486db 100644 --- a/src/pom.xml +++ b/src/pom.xml @@ -23,7 +23,6 @@ 2021.0.8 2.7.18 2.15.3 - 3.2.6 2.24.0-CLOUD 2.24.0-CLOUD 30.0 @@ -110,21 +109,6 @@ pom import - - com.playtika.reactivefeign - feign-reactor-cloud - ${feign-reactor.version} - - - com.playtika.reactivefeign - feign-reactor-spring-configuration - ${feign-reactor.version} - - - com.playtika.reactivefeign - feign-reactor-webclient - ${feign-reactor.version} - org.projectlombok lombok diff --git a/src/starters/catalog-backend/pom.xml b/src/starters/catalog-backend/pom.xml index 2b855c08c..c0d6f3c91 100644 --- a/src/starters/catalog-backend/pom.xml +++ b/src/starters/catalog-backend/pom.xml @@ -31,18 +31,4 @@ gs-cloud-catalog-events - - - catalog-service - - false - - - - org.geoserver.cloud.catalog.backend - gs-cloud-catalog-backend-catalog-service - - - - diff --git a/src/starters/pom.xml b/src/starters/pom.xml index 5f2507567..a5ae359d0 100644 --- a/src/starters/pom.xml +++ b/src/starters/pom.xml @@ -16,7 +16,6 @@ vector-formats raster-formats webmvc - reactive wms-extensions security diff --git a/src/starters/reactive/README.md b/src/starters/reactive/README.md deleted file mode 100644 index 54f89df05..000000000 --- a/src/starters/reactive/README.md +++ /dev/null @@ -1,3 +0,0 @@ -# gs-cloud-starter-reactive - -Spring auto-configuration of GeoServer environment for WebFlux reactive GeoServer microservices diff --git a/src/starters/reactive/pom.xml b/src/starters/reactive/pom.xml deleted file mode 100644 index 136e1ba70..000000000 --- a/src/starters/reactive/pom.xml +++ /dev/null @@ -1,65 +0,0 @@ - - - 4.0.0 - - org.geoserver.cloud - gs-cloud-starters - ${revision} - - gs-cloud-starter-reactive - jar - Provides auto-configuration for WebFlux based reactive GeoServer microservices - - - org.geoserver.cloud - gs-cloud-spring-boot-starter - - - org.geoserver.cloud - gs-cloud-starter-catalog-backend - - - org.springframework.boot - spring-boot-starter-webflux - - - org.springframework.cloud - spring-cloud-starter-netflix-eureka-client - - - org.springframework.cloud - spring-cloud-loadbalancer - - - org.springframework.cloud - spring-cloud-config-client - - - org.springframework.retry - spring-retry - - - org.springframework.boot - spring-boot-starter-aop - - - org.springframework.boot - spring-boot-starter-actuator - - - org.springframework.boot - spring-boot-autoconfigure-processor - true - - - - javax.servlet - javax.servlet-api - - - io.projectreactor - reactor-test - test - - - diff --git a/src/starters/reactive/src/main/java/org/geoserver/cloud/autoconfigure/core/ReactiveGeoServerMainAutoConfiguration.java b/src/starters/reactive/src/main/java/org/geoserver/cloud/autoconfigure/core/ReactiveGeoServerMainAutoConfiguration.java deleted file mode 100644 index 593b9e1fc..000000000 --- a/src/starters/reactive/src/main/java/org/geoserver/cloud/autoconfigure/core/ReactiveGeoServerMainAutoConfiguration.java +++ /dev/null @@ -1,25 +0,0 @@ -/* - * (c) 2020 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.cloud.autoconfigure.core; - -import org.geoserver.cloud.autoconfigure.catalog.backend.core.GeoServerBackendAutoConfiguration; -import org.geoserver.cloud.config.catalog.backend.core.GeoServerBackendConfigurer; -import org.geoserver.cloud.config.main.GeoServerMainModuleConfiguration; -import org.springframework.boot.autoconfigure.AutoConfiguration; -import org.springframework.boot.autoconfigure.EnableAutoConfiguration; -import org.springframework.context.annotation.Import; - -/** - * {@link EnableAutoConfiguration Auto-configuration} for the registration of the GeoServer main - * module (as in the {@code gs-main.jar} file) spring beans to work on reactive (servlet-less) - * applications. - * - *

Requires the correct configuration and enablement of a {@link GeoServerBackendConfigurer} - * - * @see GeoServerMainModuleConfiguration - */ -@AutoConfiguration(after = GeoServerBackendAutoConfiguration.class) -@Import({GeoServerMainModuleConfiguration.class}) -public class ReactiveGeoServerMainAutoConfiguration {} diff --git a/src/starters/reactive/src/main/java/org/geoserver/cloud/config/main/GeoServerMainModuleConfiguration.java b/src/starters/reactive/src/main/java/org/geoserver/cloud/config/main/GeoServerMainModuleConfiguration.java deleted file mode 100644 index 32683aeea..000000000 --- a/src/starters/reactive/src/main/java/org/geoserver/cloud/config/main/GeoServerMainModuleConfiguration.java +++ /dev/null @@ -1,62 +0,0 @@ -/* - * (c) 2020 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.cloud.config.main; - -import org.geoserver.catalog.Catalog; -import org.geoserver.catalog.SLDHandler; -import org.geoserver.catalog.SLDPackageHandler; -import org.geoserver.cloud.config.catalog.backend.core.GeoServerBackendConfigurer; -import org.geoserver.config.CatalogTimeStampUpdater; -import org.geoserver.platform.resource.SimpleResourceNotificationDispatcher; -import org.springframework.beans.factory.annotation.Qualifier; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; - -/** - * A pure java configuration for the GeoServer {@link Catalog} that can be used in a WebFlux web - * application by avoiding any reference to spring-webmvc classes (like {@code - * org.geoserver.ows.Dispatcher} which is an mvc AbstractController). - * - *

Note this configuration is intended to be used solely in WebFlux based services. All catalog - * and config backend configuration is relied upon en enabled {@link GeoServerBackendConfigurer} - * {@code @Configuration}, loaded either explicitly or, preferably, through one of the - * auto-configurations provided in {@code starter-catalog-backends} - */ -@Configuration -public class GeoServerMainModuleConfiguration { - - // TODO: revisit, provide an appropriate notification dispatcher in for the event bus - @Bean - org.geoserver.platform.resource.ResourceNotificationDispatcher - resourceNotificationDispatcher() { - return new SimpleResourceNotificationDispatcher(); - } - - @Bean - CatalogTimeStampUpdater catalogTimeStampUpdater(@Qualifier("catalog") Catalog catalog) { - return new CatalogTimeStampUpdater(catalog); - } - - // - // - // - // - @Bean - SLDHandler sldHandler() { - return new SLDHandler(); - } - - @Bean - SLDPackageHandler sldPackageHandler() { - return new SLDPackageHandlerHack(sldHandler()); - } - - /** HACK: Class to overcome the protected access to SLDPackageHandler's constructor */ - private static class SLDPackageHandlerHack extends SLDPackageHandler { - protected SLDPackageHandlerHack(SLDHandler sldHandler) { - super(sldHandler); - } - } -} diff --git a/src/starters/reactive/src/main/resources/META-INF/spring.factories b/src/starters/reactive/src/main/resources/META-INF/spring.factories deleted file mode 100644 index 5e25730a3..000000000 --- a/src/starters/reactive/src/main/resources/META-INF/spring.factories +++ /dev/null @@ -1,2 +0,0 @@ -org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ -org.geoserver.cloud.autoconfigure.core.ReactiveGeoServerMainAutoConfiguration \ No newline at end of file diff --git a/src/starters/reactive/src/test/java/org/geoserver/cloud/autoconfigure/core/GeoServerMainAutoConfigurationTest.java b/src/starters/reactive/src/test/java/org/geoserver/cloud/autoconfigure/core/GeoServerMainAutoConfigurationTest.java deleted file mode 100644 index f67f3993f..000000000 --- a/src/starters/reactive/src/test/java/org/geoserver/cloud/autoconfigure/core/GeoServerMainAutoConfigurationTest.java +++ /dev/null @@ -1,54 +0,0 @@ -/* - * (c) 2020 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.cloud.autoconfigure.core; - -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.instanceOf; -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertTrue; - -import org.geoserver.catalog.Catalog; -import org.geoserver.catalog.CatalogFacade; -import org.geoserver.catalog.impl.LocalWorkspaceCatalog; -import org.geoserver.cloud.test.TestConfiguration; -import org.junit.jupiter.api.Test; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.autoconfigure.EnableAutoConfiguration; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.boot.web.reactive.context.ReactiveWebApplicationContext; -import org.springframework.context.ApplicationContext; -import org.springframework.test.context.ActiveProfiles; -import org.springframework.web.context.WebApplicationContext; - -@SpringBootTest(classes = TestConfiguration.class) -@EnableAutoConfiguration -@ActiveProfiles("test") // see bootstrap-test.yml -class GeoServerMainAutoConfigurationTest { - - private @Autowired ApplicationContext context; - - @Test - void testContext() { - assertFalse(context instanceof WebApplicationContext); - assertTrue(context instanceof ReactiveWebApplicationContext); - } - - @Test - void rawCatalog() { - Catalog catalog = (Catalog) context.getBean("rawCatalog"); - - assertThat(catalog, instanceOf(org.geoserver.catalog.plugin.CatalogPlugin.class)); - CatalogFacade rawCatalogFacade = context.getBean(CatalogFacade.class); - assertThat( - rawCatalogFacade, - instanceOf(org.geoserver.catalog.plugin.DefaultMemoryCatalogFacade.class)); - } - - @Test - void catalog() { - Catalog catalog = (Catalog) context.getBean("catalog"); - assertThat(catalog, instanceOf(LocalWorkspaceCatalog.class)); - } -} diff --git a/src/starters/reactive/src/test/java/org/geoserver/cloud/test/TestConfiguration.java b/src/starters/reactive/src/test/java/org/geoserver/cloud/test/TestConfiguration.java deleted file mode 100644 index 55b2dceac..000000000 --- a/src/starters/reactive/src/test/java/org/geoserver/cloud/test/TestConfiguration.java +++ /dev/null @@ -1,32 +0,0 @@ -/* - * (c) 2020 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.cloud.test; - -import org.springframework.boot.actuate.autoconfigure.security.reactive.ReactiveManagementWebSecurityAutoConfiguration; -import org.springframework.boot.autoconfigure.EnableAutoConfiguration; -import org.springframework.boot.autoconfigure.security.reactive.ReactiveSecurityAutoConfiguration; -import org.springframework.boot.autoconfigure.security.reactive.ReactiveUserDetailsServiceAutoConfiguration; -import org.springframework.cloud.client.loadbalancer.LoadBalanced; -import org.springframework.cloud.client.loadbalancer.reactive.LoadBalancerBeanPostProcessorAutoConfiguration; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.web.reactive.function.client.WebClient; - -@Configuration -@EnableAutoConfiguration( - exclude = { - ReactiveSecurityAutoConfiguration.class, - ReactiveManagementWebSecurityAutoConfiguration.class, - ReactiveUserDetailsServiceAutoConfiguration.class, - LoadBalancerBeanPostProcessorAutoConfiguration.class - }) -public class TestConfiguration { - - @Bean - @LoadBalanced - public WebClient.Builder loadBalancedWebClientBuilder() { - return WebClient.builder(); - } -} diff --git a/src/starters/reactive/src/test/resources/application.yml b/src/starters/reactive/src/test/resources/application.yml deleted file mode 100644 index ca1a46790..000000000 --- a/src/starters/reactive/src/test/resources/application.yml +++ /dev/null @@ -1,38 +0,0 @@ -spring: - main: - web-application-type: REACTIVE - banner-mode: off - allow-bean-definition-overriding: true - allow-circular-references: true # false by default since spring-boot 2.6.0, breaks geoserver initialization - cloud.config.enabled: false - cloud.config.discovery.enabled: false - cloud.bus.enabled: false - autoconfigure: - exclude: - - org.springframework.boot.autoconfigure.security.reactive.ReactiveSecurityAutoConfiguration - - org.springframework.boot.autoconfigure.security.reactive.ReactiveUserDetailsServiceAutoConfiguration - - org.springframework.boot.actuate.autoconfigure.security.reactive.ReactiveManagementWebSecurityAutoConfiguration - - org.springframework.boot.autoconfigure.security.servlet.UserDetailsServiceAutoConfiguration -eureka.client.enabled: false - -geoserver: - catalog: - isolated: true - # Disable advertised catalog, it checks the org.geoserver.ows.Dispatcher.REQUEST to check if an OWS is in progress, - # which can never be the case, and causes a java.lang.NoClassDefFoundError on org.springframework.web.servlet.mvc.AbstractController - advertised: false - localWorkspace: true - secure: false - backend: - data-directory: - enabled: true - location: ${data_directory:${java.io.tmpdir}/geoserver_cloud_data_directory} - jdbcconfig.enabled: false - -logging: - level: - root: WARN - org.geoserver.platform: ERROR - org.geoserver.cloud: INFO - org.geoserver.cloud.config.factory: INFO - org.springframework.test: ERROR \ No newline at end of file diff --git a/src/starters/reactive/src/test/resources/logback-test.xml b/src/starters/reactive/src/test/resources/logback-test.xml deleted file mode 100644 index c299d4da7..000000000 --- a/src/starters/reactive/src/test/resources/logback-test.xml +++ /dev/null @@ -1,15 +0,0 @@ - - - - %d{HH:mm:ss.SSS} [%thread] %-5level %logger - %msg%n - - - - - - - - - - - \ No newline at end of file