Rename pgsql backend as pgconfig

This commit is contained in:
Gabriel Roldan 2024-01-30 21:23:36 -03:00
parent 246839cf5f
commit a906728923
70 changed files with 615 additions and 820 deletions

View File

@ -121,7 +121,7 @@
</dependency>
<dependency>
<groupId>org.geoserver.cloud.catalog.backend</groupId>
<artifactId>gs-cloud-catalog-backend-pgsql</artifactId>
<artifactId>gs-cloud-catalog-backend-pgconfig</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>

View File

@ -97,7 +97,7 @@
</dependency>
<dependency>
<groupId>org.geoserver.cloud.catalog.backend</groupId>
<artifactId>gs-cloud-catalog-backend-pgsql</artifactId>
<artifactId>gs-cloud-catalog-backend-pgconfig</artifactId>
</dependency>
<dependency>
<groupId>org.geoserver.cloud.gwc</groupId>

View File

@ -4,6 +4,8 @@
*/
package org.geoserver.cloud.autoconfigure.metrics.catalog;
import io.micrometer.core.annotation.Timed;
import lombok.NonNull;
import org.geoserver.catalog.Catalog;
@ -14,6 +16,7 @@ import org.springframework.boot.actuate.autoconfigure.metrics.CompositeMeterRegi
import org.springframework.boot.actuate.autoconfigure.metrics.MetricsAutoConfiguration;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
@ -26,6 +29,7 @@ import org.springframework.context.annotation.Bean;
*/
@AutoConfiguration(
after = {MetricsAutoConfiguration.class, CompositeMeterRegistryAutoConfiguration.class})
@ConditionalOnClass(Timed.class)
@ConditionalOnGeoServerMetricsEnabled
@EnableConfigurationProperties(GeoSeverMetricsConfigProperties.class)
public class CatalogMetricsAutoConfiguration {

View File

@ -19,6 +19,7 @@ import org.geoserver.config.util.XStreamPersisterFactory;
import org.geoserver.platform.GeoServerEnvironment;
import org.geoserver.platform.GeoServerExtensions;
import org.geoserver.platform.GeoServerResourceLoader;
import org.geoserver.platform.resource.ResourceStoreFactory;
import org.geoserver.security.SecureCatalogImpl;
import org.geoserver.security.impl.DataAccessRuleDAO;
import org.geoserver.security.impl.DefaultResourceAccessManager;
@ -181,4 +182,9 @@ public class CoreBackendConfiguration {
GeoServerDataDirectory dataDirectory(GeoServerResourceLoader resourceLoader) {
return new GeoServerDataDirectory(resourceLoader);
}
@Bean
ResourceStoreFactory resourceStore() {
return new ResourceStoreFactory();
}
}

View File

@ -6,7 +6,7 @@
<artifactId>gs-cloud-catalog-backends</artifactId>
<version>${revision}</version>
</parent>
<artifactId>gs-cloud-catalog-backend-pgsql</artifactId>
<artifactId>gs-cloud-catalog-backend-pgconfig</artifactId>
<packaging>jar</packaging>
<description>PostgreSQL catalog backend</description>
<dependencies>
@ -50,6 +50,15 @@
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
</dependency>
<dependency>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.github.ben-manes.caffeine</groupId>
<artifactId>caffeine</artifactId>
</dependency>
<dependency>
<!-- to access gwc-core transitively without having to specify the gwc version -->
<!-- required to implement a TileLayerCatalog postgres backend -->
@ -107,5 +116,49 @@
<artifactId>junit-vintage-engine</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.awaitility</groupId>
<artifactId>awaitility</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>build-helper-maven-plugin</artifactId>
<executions>
<execution>
<goals>
<goal>add-source</goal>
</goals>
<phase>generate-sources</phase>
<configuration>
<sources>
<source>${project.build.directory}/generated-sources-mapstruct</source>
</sources>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<generatedSourcesDirectory>${project.build.directory}/generated-sources-mapstruct</generatedSourcesDirectory>
<annotationProcessorPaths>
<path>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>${lombok.version}</version>
</path>
<path>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct-processor</artifactId>
<version>${mapstruct.version}</version>
</path>
</annotationProcessorPaths>
</configuration>
</plugin>
</plugins>
</build>
</project>

View File

@ -2,7 +2,7 @@
* (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.pgsql;
package org.geoserver.cloud.autoconfigure.catalog.backend.pgconfig;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;

View File

@ -2,10 +2,10 @@
* (c) 2023 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.pgsql;
package org.geoserver.cloud.autoconfigure.catalog.backend.pgconfig;
import org.geoserver.cloud.config.catalog.backend.core.CatalogProperties;
import org.geoserver.cloud.config.catalog.backend.pgsql.PgsqlBackendConfiguration;
import org.geoserver.cloud.config.catalog.backend.pgconfig.PgsqlBackendConfiguration;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Import;

View File

@ -2,9 +2,9 @@
* (c) 2023 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.pgsql;
package org.geoserver.cloud.autoconfigure.catalog.backend.pgconfig;
import org.geoserver.cloud.config.catalog.backend.pgsql.PgsqlDataSourceConfiguration;
import org.geoserver.cloud.config.catalog.backend.pgconfig.PgsqlDataSourceConfiguration;
import org.geoserver.cloud.config.jndidatasource.JNDIDataSourceAutoConfiguration;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.context.annotation.Import;

View File

@ -2,9 +2,9 @@
* (c) 2023 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.pgsql;
package org.geoserver.cloud.autoconfigure.catalog.backend.pgconfig;
import org.geoserver.cloud.config.catalog.backend.pgsql.DatabaseMigrationConfiguration;
import org.geoserver.cloud.config.catalog.backend.pgconfig.DatabaseMigrationConfiguration;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.context.annotation.Import;

View File

@ -2,7 +2,7 @@
* (c) 2023 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.backend.pgsql;
package org.geoserver.cloud.backend.pgconfig;
import lombok.NonNull;
import lombok.RequiredArgsConstructor;
@ -16,8 +16,8 @@ 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.backend.pgsql.catalog.PgsqlCatalogFacade;
import org.geoserver.cloud.backend.pgsql.config.PgsqlGeoServerFacade;
import org.geoserver.cloud.backend.pgconfig.catalog.PgsqlCatalogFacade;
import org.geoserver.cloud.backend.pgconfig.config.PgsqlGeoServerFacade;
import org.geoserver.config.plugin.GeoServerImpl;
import org.springframework.jdbc.core.JdbcTemplate;

View File

@ -2,18 +2,18 @@
* (c) 2023 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.backend.pgsql.catalog;
package org.geoserver.cloud.backend.pgconfig.catalog;
import lombok.NonNull;
import org.geoserver.catalog.plugin.RepositoryCatalogFacadeImpl;
import org.geoserver.cloud.backend.pgsql.catalog.repository.PgsqlLayerGroupRepository;
import org.geoserver.cloud.backend.pgsql.catalog.repository.PgsqlLayerRepository;
import org.geoserver.cloud.backend.pgsql.catalog.repository.PgsqlNamespaceRepository;
import org.geoserver.cloud.backend.pgsql.catalog.repository.PgsqlResourceRepository;
import org.geoserver.cloud.backend.pgsql.catalog.repository.PgsqlStoreRepository;
import org.geoserver.cloud.backend.pgsql.catalog.repository.PgsqlStyleRepository;
import org.geoserver.cloud.backend.pgsql.catalog.repository.PgsqlWorkspaceRepository;
import org.geoserver.cloud.backend.pgconfig.catalog.repository.PgsqlLayerGroupRepository;
import org.geoserver.cloud.backend.pgconfig.catalog.repository.PgsqlLayerRepository;
import org.geoserver.cloud.backend.pgconfig.catalog.repository.PgsqlNamespaceRepository;
import org.geoserver.cloud.backend.pgconfig.catalog.repository.PgsqlResourceRepository;
import org.geoserver.cloud.backend.pgconfig.catalog.repository.PgsqlStoreRepository;
import org.geoserver.cloud.backend.pgconfig.catalog.repository.PgsqlStyleRepository;
import org.geoserver.cloud.backend.pgconfig.catalog.repository.PgsqlWorkspaceRepository;
import org.springframework.jdbc.core.JdbcTemplate;
/**

View File

@ -2,7 +2,7 @@
* (c) 2023 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.backend.pgsql.catalog.filter;
package org.geoserver.cloud.backend.pgconfig.catalog.filter;
import org.geotools.api.filter.Filter;
import org.geotools.api.filter.expression.PropertyName;

View File

@ -2,7 +2,7 @@
* (c) 2023 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.backend.pgsql.catalog.filter;
package org.geoserver.cloud.backend.pgconfig.catalog.filter;
import lombok.experimental.UtilityClass;

View File

@ -2,7 +2,7 @@
* (c) 2023 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.backend.pgsql.catalog.filter;
package org.geoserver.cloud.backend.pgconfig.catalog.filter;
import lombok.Value;

View File

@ -2,12 +2,12 @@
* (c) 2023 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.backend.pgsql.catalog.filter;
package org.geoserver.cloud.backend.pgconfig.catalog.filter;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import org.geoserver.cloud.backend.pgsql.catalog.filter.PgsqlFilterToSQL.Result;
import org.geoserver.cloud.backend.pgconfig.catalog.filter.PgsqlFilterToSQL.Result;
import org.geotools.api.filter.Filter;
import org.geotools.filter.visitor.SimplifyingFilterVisitor;

View File

@ -2,7 +2,7 @@
* (c) 2023 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.backend.pgsql.catalog.filter;
package org.geoserver.cloud.backend.pgconfig.catalog.filter;
import org.geotools.api.filter.BinaryComparisonOperator;
import org.geotools.api.filter.Filter;

View File

@ -2,7 +2,7 @@
* (c) 2023 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.backend.pgsql.catalog.repository;
package org.geoserver.cloud.backend.pgconfig.catalog.repository;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
@ -13,6 +13,7 @@ import org.geoserver.catalog.CatalogInfo;
import org.geoserver.catalog.LayerGroupInfo;
import org.geoserver.catalog.LayerInfo;
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;
@ -36,14 +37,18 @@ import java.util.function.Function;
/**
* @since 1.4
*/
class CatalogInfoRowMapper {
public final class CatalogInfoRowMapper {
protected static final ObjectMapper infoMapper = ObjectMapperUtil.newObjectMapper();
protected static final ObjectMapper objectMapper = ObjectMapperUtil.newObjectMapper();
// TODO: limit the amount of cached objects
protected Map<String, CatalogInfo> cache = new HashMap<>();
private Map<String, CatalogInfo> cache = new HashMap<>();
protected @Setter Function<String, Optional<StyleInfo>> styleLoader;
private @Setter Function<String, Optional<StyleInfo>> styleLoader;
private CatalogInfoRowMapper() {
// private constructor
}
protected <T extends CatalogInfo> T resolveCached(
String id, Class<T> clazz, ResultSet rs, Function<ResultSet, T> loader) {
@ -68,9 +73,9 @@ class CatalogInfoRowMapper {
* <p>Expects the following columns:
*
* <pre>{@code
* Column | Type | Collation | Nullable | Default
* ----------------------+----------+-----------+----------+---------
* workspace | jsonb | | |
* Column | Type |
* ----------------------+------
* workspace | jsonb |
* }</pre>
*/
public WorkspaceInfo mapWorkspace(ResultSet rs, int rowNum) throws SQLException {
@ -97,9 +102,9 @@ class CatalogInfoRowMapper {
* Expects the following columns:
*
* <pre>{@code
* Column | Type | Collation | Nullable | Default
* ----------------------+----------+-----------+----------+---------
* namespace | jsonb | | |
* Column | Type |
* -----------------+----------+
* namespace | jsonb |
* }</pre>
*/
public NamespaceInfo mapNamespace(ResultSet rs, int rowNum) throws SQLException {
@ -126,10 +131,10 @@ class CatalogInfoRowMapper {
* Expects the following columns:
*
* <pre>{@code
* Column | Type | Collation | Nullable | Default
* ----------------------+----------+-----------+----------+---------
* style | jsonb | | |
* workspace | jsonb | | |
* Column | Type |
* -----------------+----------+
* style | jsonb |
* workspace | jsonb |
* }</pre>
*/
public StyleInfo mapStyle(ResultSet rs, int rowNum) throws SQLException {
@ -172,10 +177,10 @@ class CatalogInfoRowMapper {
* Expects the following columns:
*
* <pre>{@code
* Column | Type | Collation | Nullable | Default
* ----------------------+----------+-----------+----------+---------
* store | jsonb | | |
* workspace | jsonb | | |
* Column | Type |
* -----------------+----------+
* store | jsonb |
* workspace | jsonb |
* }</pre>
*/
public StoreInfo mapStore(ResultSet rs, int rowNum) throws SQLException {
@ -207,12 +212,12 @@ class CatalogInfoRowMapper {
* Expects the following columns:
*
* <pre>{@code
* Column | Type | Collation | Nullable | Default
* ----------------------+----------+-----------+----------+---------
* resource | jsonb | | |
* store | jsonb | | |
* workspace | jsonb | | |
* namespace | jsonb | | |
* Column | Type |
* -----------------+----------+
* resource | jsonb |
* store | jsonb |
* workspace | jsonb |
* namespace | jsonb |
* }</pre>
*/
public ResourceInfo mapResource(ResultSet rs, int rowNum) throws SQLException {
@ -259,14 +264,41 @@ class CatalogInfoRowMapper {
* Expects the following columns:
*
* <pre>{@code
* Column | Type | Collation | Nullable | Default
* ----------------------+----------+-----------+----------+---------
* publishedinfo | jsonb | | |
* resource | jsonb | | |
* store | jsonb | | |
* workspace | jsonb | | |
* namespace | jsonb | | |
* defaultStyle | jsonb | | |
* Column | Type |
* ----------------------+------
* @type | text |
* publishedinfo | jsonb |
* workspace | jsonb |
* resource | jsonb |
* store | jsonb |
* namespace | jsonb |
* defaultStyle | jsonb |
* }</pre>
*
* @see #mapLayer(ResultSet, int)
* @see #mapLayerGroup(ResultSet, int)
*/
public PublishedInfo mapPublishedInfo(ResultSet rs, int rowNum) throws SQLException {
final String type = rs.getString("@type");
return switch (type) {
case "LayerInfo" -> mapLayer(rs, rowNum);
case "LayerGroupInfo" -> mapLayerGroup(rs, rowNum);
default -> throw new IllegalArgumentException("Unexpected value: " + type);
};
}
/**
* Expects the following columns:
*
* <pre>{@code
* Column | Type |
* ----------------------+------
* publishedinfo | jsonb |
* resource | jsonb |
* store | jsonb |
* workspace | jsonb |
* namespace | jsonb |
* defaultStyle | jsonb |
* }</pre>
*/
public LayerInfo mapLayer(ResultSet rs, int rowNum) throws SQLException {
@ -277,6 +309,24 @@ class CatalogInfoRowMapper {
}
}
/**
* Expects the following columns:
*
* <pre>{@code
* Column | Type |
* ----------------------+------
* publishedinfo | jsonb |
* workspace | jsonb |
* }</pre>
*/
public LayerGroupInfo mapLayerGroup(ResultSet rs, int rowNum) throws SQLException {
try {
return mapLayerGroup(rs);
} catch (UncheckedSqlException e) {
throw e.getCause();
}
}
protected LayerInfo mapLayer(ResultSet rs) {
LayerInfo layer;
try {
@ -329,24 +379,6 @@ class CatalogInfoRowMapper {
}
}
/**
* Expects the following columns:
*
* <pre>{@code
* Column | Type | Collation | Nullable | Default
* ----------------------+----------+-----------+----------+---------
* publishedinfo | jsonb | | |
* workspace | jsonb | | |
* }</pre>
*/
public LayerGroupInfo mapLayerGroup(ResultSet rs, int rowNum) throws SQLException {
try {
return mapLayerGroup(rs);
} catch (UncheckedSqlException e) {
throw e.getCause();
}
}
protected LayerGroupInfo mapLayerGroup(ResultSet rs) {
LayerGroupInfo layergroup;
try {
@ -369,7 +401,7 @@ class CatalogInfoRowMapper {
protected <V> V decode(String encoded, Class<V> valueType) {
try {
return null == encoded ? null : infoMapper.readValue(encoded, valueType);
return null == encoded ? null : objectMapper.readValue(encoded, valueType);
} catch (JsonProcessingException e) {
throw new UncheckedIOException(e);
}
@ -401,7 +433,17 @@ class CatalogInfoRowMapper {
return mapper::mapLayer;
}
public static RowMapper<LayerGroupInfo> layerGroup() {
return new CatalogInfoRowMapper()::mapLayerGroup;
public static RowMapper<LayerGroupInfo> layerGroup(
Function<String, Optional<StyleInfo>> styleLoader) {
CatalogInfoRowMapper mapper = new CatalogInfoRowMapper();
mapper.setStyleLoader(styleLoader);
return mapper::mapLayerGroup;
}
public static RowMapper<PublishedInfo> published(
Function<String, Optional<StyleInfo>> styleLoader) {
CatalogInfoRowMapper mapper = new CatalogInfoRowMapper();
mapper.setStyleLoader(styleLoader);
return mapper::mapPublishedInfo;
}
}

View File

@ -2,7 +2,7 @@
* (c) 2023 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.backend.pgsql.catalog.repository;
package org.geoserver.cloud.backend.pgconfig.catalog.repository;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
@ -15,7 +15,7 @@ import org.geoserver.catalog.impl.ClassMappings;
import org.geoserver.catalog.plugin.CatalogInfoRepository;
import org.geoserver.catalog.plugin.Patch;
import org.geoserver.catalog.plugin.Query;
import org.geoserver.cloud.backend.pgsql.catalog.filter.PgsqlQueryBuilder;
import org.geoserver.cloud.backend.pgconfig.catalog.filter.PgsqlQueryBuilder;
import org.geotools.api.filter.Filter;
import org.geotools.api.filter.sort.SortBy;
import org.geotools.api.filter.sort.SortOrder;

View File

@ -2,7 +2,7 @@
* (c) 2023 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.backend.pgsql.catalog.repository;
package org.geoserver.cloud.backend.pgconfig.catalog.repository;
import lombok.NonNull;
@ -86,6 +86,7 @@ public class PgsqlLayerGroupRepository extends PgsqlCatalogInfoRepository<LayerG
@Override
protected RowMapper<LayerGroupInfo> newRowMapper() {
return CatalogInfoRowMapper.layerGroup();
PgsqlStyleRepository styleLoader = new PgsqlStyleRepository(template);
return CatalogInfoRowMapper.layerGroup(styleLoader::findById);
}
}

View File

@ -2,7 +2,7 @@
* (c) 2023 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.backend.pgsql.catalog.repository;
package org.geoserver.cloud.backend.pgconfig.catalog.repository;
import lombok.NonNull;

View File

@ -2,7 +2,7 @@
* (c) 2023 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.backend.pgsql.catalog.repository;
package org.geoserver.cloud.backend.pgconfig.catalog.repository;
import lombok.NonNull;

View File

@ -2,7 +2,7 @@
* (c) 2023 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.backend.pgsql.catalog.repository;
package org.geoserver.cloud.backend.pgconfig.catalog.repository;
import lombok.NonNull;

View File

@ -2,7 +2,7 @@
* (c) 2023 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.backend.pgsql.catalog.repository;
package org.geoserver.cloud.backend.pgconfig.catalog.repository;
import lombok.NonNull;

View File

@ -2,7 +2,7 @@
* (c) 2023 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.backend.pgsql.catalog.repository;
package org.geoserver.cloud.backend.pgconfig.catalog.repository;
import lombok.NonNull;

View File

@ -2,7 +2,7 @@
* (c) 2023 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.backend.pgsql.catalog.repository;
package org.geoserver.cloud.backend.pgconfig.catalog.repository;
import lombok.NonNull;

View File

@ -2,7 +2,7 @@
* (c) 2023 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.backend.pgsql.catalog.repository;
package org.geoserver.cloud.backend.pgconfig.catalog.repository;
import java.sql.SQLException;

View File

@ -2,7 +2,7 @@
* (c) 2023 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.backend.pgsql.config;
package org.geoserver.cloud.backend.pgconfig.config;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;

View File

@ -2,7 +2,7 @@
* (c) 2023 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.backend.pgsql.config;
package org.geoserver.cloud.backend.pgconfig.config;
import lombok.NonNull;

View File

@ -2,7 +2,7 @@
* (c) 2023 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.backend.pgsql.config;
package org.geoserver.cloud.backend.pgconfig.config;
import lombok.NonNull;
import lombok.RequiredArgsConstructor;

View File

@ -1,4 +1,4 @@
package org.geoserver.cloud.backend.pgsql.resource;
package org.geoserver.cloud.backend.pgconfig.resource;
import com.google.common.base.Preconditions;

View File

@ -2,7 +2,7 @@
* (c) 2023 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.backend.pgsql.resource;
package org.geoserver.cloud.backend.pgconfig.resource;
import lombok.extern.slf4j.Slf4j;

View File

@ -2,7 +2,7 @@
* (c) 2023 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.backend.pgsql.resource;
package org.geoserver.cloud.backend.pgconfig.resource;
import lombok.EqualsAndHashCode;
import lombok.Getter;

View File

@ -2,7 +2,7 @@
* (c) 2023 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.backend.pgsql.resource;
package org.geoserver.cloud.backend.pgconfig.resource;
import lombok.NonNull;
import lombok.RequiredArgsConstructor;

View File

@ -2,7 +2,7 @@
* (c) 2023 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.backend.pgsql.resource;
package org.geoserver.cloud.backend.pgconfig.resource;
import com.google.common.base.Preconditions;

View File

@ -2,7 +2,7 @@
* (c) 2023 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.pgsql;
package org.geoserver.cloud.config.catalog.backend.pgconfig;
import lombok.RequiredArgsConstructor;

View File

@ -2,7 +2,7 @@
* (c) 2023 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.pgsql;
package org.geoserver.cloud.config.catalog.backend.pgconfig;
import lombok.NonNull;
import lombok.RequiredArgsConstructor;

View File

@ -2,7 +2,7 @@
* (c) 2023 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.pgsql;
package org.geoserver.cloud.config.catalog.backend.pgconfig;
import lombok.extern.slf4j.Slf4j;
@ -10,16 +10,16 @@ import org.geoserver.GeoServerConfigurationLock;
import org.geoserver.catalog.plugin.CatalogPlugin;
import org.geoserver.catalog.plugin.ExtendedCatalogFacade;
import org.geoserver.catalog.plugin.locking.LockProviderGeoServerConfigurationLock;
import org.geoserver.cloud.backend.pgsql.PgsqlBackendBuilder;
import org.geoserver.cloud.backend.pgsql.config.PgsqlConfigRepository;
import org.geoserver.cloud.backend.pgsql.config.PgsqlGeoServerFacade;
import org.geoserver.cloud.backend.pgsql.config.PgsqlUpdateSequence;
import org.geoserver.cloud.backend.pgsql.resource.FileSystemResourceStoreCache;
import org.geoserver.cloud.backend.pgsql.resource.PgsqlLockProvider;
import org.geoserver.cloud.backend.pgsql.resource.PgsqlResourceStore;
import org.geoserver.cloud.backend.pgconfig.PgsqlBackendBuilder;
import org.geoserver.cloud.backend.pgconfig.config.PgsqlConfigRepository;
import org.geoserver.cloud.backend.pgconfig.config.PgsqlGeoServerFacade;
import org.geoserver.cloud.backend.pgconfig.config.PgsqlUpdateSequence;
import org.geoserver.cloud.backend.pgconfig.resource.FileSystemResourceStoreCache;
import org.geoserver.cloud.backend.pgconfig.resource.PgsqlLockProvider;
import org.geoserver.cloud.backend.pgconfig.resource.PgsqlResourceStore;
import org.geoserver.cloud.config.catalog.backend.core.CatalogProperties;
import org.geoserver.cloud.config.catalog.backend.core.GeoServerBackendConfigurer;
import org.geoserver.cloud.config.catalog.backend.pgsql.DatabaseMigrationConfiguration.Migrations;
import org.geoserver.cloud.config.catalog.backend.pgconfig.DatabaseMigrationConfiguration.Migrations;
import org.geoserver.config.GeoServerLoader;
import org.geoserver.platform.GeoServerResourceLoader;
import org.geoserver.platform.resource.LockProvider;

View File

@ -2,7 +2,7 @@
* (c) 2023 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.pgsql;
package org.geoserver.cloud.config.catalog.backend.pgconfig;
import lombok.Data;

View File

@ -2,7 +2,7 @@
* (c) 2023 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.pgsql;
package org.geoserver.cloud.config.catalog.backend.pgconfig;
import com.zaxxer.hikari.HikariDataSource;

View File

@ -2,7 +2,7 @@
* (c) 2023 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.pgsql;
package org.geoserver.cloud.config.catalog.backend.pgconfig;
import lombok.Data;
import lombok.experimental.Accessors;
@ -45,7 +45,11 @@ public class PgsqlDatabaseMigrations {
result.migrations == null ? 0 : result.migrations.size());
}
/** */
/**
* Drops all objects (tables, views, procedures, triggers, ...) in the configured schemas.
*
* @see Flyway#clean()
*/
public void clean() {
Flyway flyway = buildFlyway();
flyway.clean();

View File

@ -2,7 +2,7 @@
* (c) 2023 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.pgsql;
package org.geoserver.cloud.config.catalog.backend.pgconfig;
import static org.geoserver.catalog.StyleInfo.DEFAULT_GENERIC;
import static org.geoserver.catalog.StyleInfo.DEFAULT_LINE;

View File

@ -2,7 +2,7 @@
* (c) 2023 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.pgsql;
package org.geoserver.cloud.config.catalog.backend.pgconfig;
import lombok.NonNull;

View File

@ -0,0 +1,5 @@
# Auto Configure
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.geoserver.cloud.autoconfigure.catalog.backend.pgconfig.PgsqlDataSourceAutoConfiguration,\
org.geoserver.cloud.autoconfigure.catalog.backend.pgconfig.PgsqlMigrationAutoConfiguration,\
org.geoserver.cloud.autoconfigure.catalog.backend.pgconfig.PgsqlBackendAutoConfiguration

View File

@ -2,27 +2,27 @@
* (c) 2023 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.pgsql;
package org.geoserver.cloud.autoconfigure.catalog.backend.pgconfig;
import static org.assertj.core.api.Assertions.assertThat;
import org.geoserver.GeoServerConfigurationLock;
import org.geoserver.catalog.plugin.CatalogPlugin;
import org.geoserver.catalog.plugin.forwarding.ResolvingCatalogFacadeDecorator;
import org.geoserver.cloud.backend.pgsql.catalog.PgsqlCatalogFacade;
import org.geoserver.cloud.backend.pgsql.config.PgsqlConfigRepository;
import org.geoserver.cloud.backend.pgsql.config.PgsqlGeoServerFacade;
import org.geoserver.cloud.backend.pgsql.config.PgsqlUpdateSequence;
import org.geoserver.cloud.backend.pgsql.resource.PgsqlLockProvider;
import org.geoserver.cloud.backend.pgsql.resource.PgsqlResourceStore;
import org.geoserver.cloud.config.catalog.backend.pgsql.PgsqlGeoServerLoader;
import org.geoserver.cloud.config.catalog.backend.pgsql.PgsqlGeoServerResourceLoader;
import org.geoserver.cloud.backend.pgconfig.catalog.PgsqlCatalogFacade;
import org.geoserver.cloud.backend.pgconfig.config.PgsqlConfigRepository;
import org.geoserver.cloud.backend.pgconfig.config.PgsqlGeoServerFacade;
import org.geoserver.cloud.backend.pgconfig.config.PgsqlUpdateSequence;
import org.geoserver.cloud.backend.pgconfig.resource.PgsqlLockProvider;
import org.geoserver.cloud.backend.pgconfig.resource.PgsqlResourceStore;
import org.geoserver.cloud.backend.pgconfig.support.PgConfigTestContainer;
import org.geoserver.cloud.config.catalog.backend.pgconfig.PgsqlGeoServerLoader;
import org.geoserver.cloud.config.catalog.backend.pgconfig.PgsqlGeoServerResourceLoader;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.boot.autoconfigure.AutoConfigurations;
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
import org.springframework.jdbc.core.JdbcTemplate;
import org.testcontainers.containers.PostgreSQLContainer;
import org.testcontainers.junit.jupiter.Container;
import org.testcontainers.junit.jupiter.Testcontainers;
@ -34,7 +34,7 @@ import org.testcontainers.junit.jupiter.Testcontainers;
@Testcontainers(disabledWithoutDocker = true)
class PgsqlBackendAutoConfigurationTest {
@Container static PostgreSQLContainer<?> container = new PostgreSQLContainer<>("postgres:15");
@Container static PgConfigTestContainer<?> container = new PgConfigTestContainer<>();
private ApplicationContextRunner runner =
new ApplicationContextRunner()
@ -46,16 +46,7 @@ class PgsqlBackendAutoConfigurationTest {
@BeforeEach
void setUp() throws Exception {
String url = container.getJdbcUrl();
String username = container.getUsername();
String password = container.getPassword();
runner =
runner.withPropertyValues( //
"geoserver.backend.pgconfig.enabled=true", //
"geoserver.backend.pgconfig.datasource.url=" + url, //
"geoserver.backend.pgconfig.datasource.username=" + username, //
"geoserver.backend.pgconfig.datasource.password=" + password //
);
runner = container.withJdbcUrlConfig(runner);
}
@Test

View File

@ -2,22 +2,20 @@
* (c) 2023 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.pgsql;
package org.geoserver.cloud.autoconfigure.catalog.backend.pgconfig;
import static org.assertj.core.api.Assertions.assertThat;
import lombok.extern.slf4j.Slf4j;
import org.geoserver.cloud.config.catalog.backend.pgsql.PgsqlDataSourceConfiguration;
import org.geoserver.cloud.config.jndi.SimpleJNDIStaticContextInitializer;
import org.geoserver.cloud.config.jndidatasource.JNDIDataSourceAutoConfiguration;
import org.geoserver.cloud.backend.pgconfig.support.PgConfigTestContainer;
import org.geoserver.cloud.config.catalog.backend.pgconfig.PgsqlDataSourceConfiguration;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.beans.BeansException;
import org.springframework.boot.autoconfigure.AutoConfigurations;
import org.springframework.boot.test.context.assertj.AssertableApplicationContext;
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
import org.testcontainers.containers.PostgreSQLContainer;
import org.testcontainers.junit.jupiter.Container;
import org.testcontainers.junit.jupiter.Testcontainers;
@ -37,7 +35,7 @@ import javax.sql.DataSource;
@Slf4j
class PgsqlDataSourceAutoConfigurationTest {
@Container static PostgreSQLContainer<?> container = new PostgreSQLContainer<>("postgres:15");
@Container static PgConfigTestContainer<?> container = new PgConfigTestContainer<>();
private ApplicationContextRunner runner =
new ApplicationContextRunner()
@ -57,16 +55,12 @@ class PgsqlDataSourceAutoConfigurationTest {
/**
* Test method for {@link
* org.geoserver.cloud.config.catalog.backend.pgsql.PgsqlDataSourceConfiguration#dataSource()}.
* org.geoserver.cloud.config.catalog.backend.pgconfig.PgsqlDataSourceConfiguration#dataSource()}.
*/
@Test
void testDataSource() {
runner.withPropertyValues( //
"geoserver.backend.pgconfig.enabled: true", //
"geoserver.backend.pgconfig.datasource.url: " + url, //
"geoserver.backend.pgconfig.datasource.username: " + username, //
"geoserver.backend.pgconfig.datasource.password: " + password //
)
container
.withJdbcUrlConfig(runner)
.run(
context -> {
assertThat(context)
@ -81,23 +75,12 @@ class PgsqlDataSourceAutoConfigurationTest {
/**
* Test method for {@link
* org.geoserver.cloud.config.catalog.backend.pgsql.PgsqlDataSourceConfiguration#jndiDataSource()}.
* org.geoserver.cloud.config.catalog.backend.pgconfig.PgsqlDataSourceConfiguration#jndiDataSource()}.
*/
@Test
void testJndiDataSource() {
runner
// enable simplejndi
.withInitializer(new SimpleJNDIStaticContextInitializer())
.withConfiguration(AutoConfigurations.of(JNDIDataSourceAutoConfiguration.class))
.withPropertyValues( //
"geoserver.backend.pgconfig.enabled: true", //
// java:comp/env/jdbc/testdb config properties
"jndi.datasources.testdb.url: " + url,
"jndi.datasources.testdb.username: " + username, //
"jndi.datasources.testdb.password: " + password, //
"jndi.datasources.testdb.enabled: true", //
// pgsql backend datasource config using jndi
"geoserver.backend.pgconfig.datasource.jndi-name: java:comp/env/jdbc/testdb")
container
.withJndiConfig(runner)
.run(
context -> {
assertThat(context)

View File

@ -2,16 +2,15 @@
* (c) 2023 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.pgsql;
package org.geoserver.cloud.autoconfigure.catalog.backend.pgconfig;
import static org.assertj.core.api.Assertions.assertThat;
import org.geoserver.cloud.config.catalog.backend.pgsql.PgsqlBackendProperties;
import org.junit.jupiter.api.BeforeEach;
import org.geoserver.cloud.backend.pgconfig.support.PgConfigTestContainer;
import org.geoserver.cloud.config.catalog.backend.pgconfig.PgsqlBackendProperties;
import org.junit.jupiter.api.Test;
import org.springframework.boot.autoconfigure.AutoConfigurations;
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
import org.testcontainers.containers.PostgreSQLContainer;
import org.testcontainers.junit.jupiter.Container;
import org.testcontainers.junit.jupiter.Testcontainers;
@ -33,7 +32,7 @@ import javax.sql.DataSource;
@Testcontainers(disabledWithoutDocker = true)
class PgsqlMigrationAutoConfigurationTest {
@Container static PostgreSQLContainer<?> container = new PostgreSQLContainer<>("postgres:15");
@Container static PgConfigTestContainer<?> container = new PgConfigTestContainer<>();
private ApplicationContextRunner runner =
new ApplicationContextRunner()
@ -42,20 +41,10 @@ class PgsqlMigrationAutoConfigurationTest {
PgsqlDataSourceAutoConfiguration.class,
PgsqlMigrationAutoConfiguration.class));
@BeforeEach
void setUp() throws Exception {}
@Test
void testMigration_enabledByDefault() {
String url = container.getJdbcUrl();
String username = container.getUsername();
String password = container.getPassword();
runner.withPropertyValues( //
"geoserver.backend.pgconfig.enabled=true", //
"geoserver.backend.pgconfig.datasource.url=" + url, //
"geoserver.backend.pgconfig.datasource.username=" + username, //
"geoserver.backend.pgconfig.datasource.password=" + password //
)
container
.withJdbcUrlConfig(runner)
.run(
context -> {
assertThat(context)

View File

@ -0,0 +1,59 @@
/*
* (c) 2023 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.backend.pgconfig.catalog;
import org.geoserver.catalog.impl.CatalogImpl;
import org.geoserver.catalog.plugin.CatalogConformanceTest;
import org.geoserver.cloud.backend.pgconfig.PgsqlBackendBuilder;
import org.geoserver.cloud.backend.pgconfig.support.PgConfigTestContainer;
import org.geotools.util.logging.Logging;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Disabled;
import org.testcontainers.junit.jupiter.Container;
import org.testcontainers.junit.jupiter.Testcontainers;
/**
* @since 1.4
*/
@Testcontainers(disabledWithoutDocker = true)
class PgsqlCatalogBackendConformanceTest extends CatalogConformanceTest {
@Container static PgConfigTestContainer<?> container = new PgConfigTestContainer<>();
@Disabled(
"""
revisit, seems to be just a problem of ordering or equals with the \
returned ft/ft2 where mockito is not throwing the expected exception
""")
@Override
public void testSaveDataStoreRollbacksBothStoreAndResources() throws Exception {}
static @BeforeAll void beforeAll() throws Exception {
try {
Logging.ALL.setLoggerFactory("org.geotools.util.logging.CommonsLoggerFactory");
} catch (ClassNotFoundException e) {
throw new IllegalStateException(e);
}
}
@Override
@BeforeEach
public void setUp() throws Exception {
container.setUp();
super.setUp();
}
@AfterEach
void cleanDb() throws Exception {
container.tearDown();
}
@Override
protected CatalogImpl createCatalog() {
return new PgsqlBackendBuilder(container.getDataSource()).createCatalog();
}
}

View File

@ -0,0 +1,50 @@
/*
* (c) 2023 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.backend.pgconfig.catalog.repository;
import static org.assertj.core.api.Assertions.assertThat;
import org.geoserver.catalog.WorkspaceInfo;
import org.geoserver.catalog.impl.WorkspaceInfoImpl;
import org.geoserver.cloud.backend.pgconfig.support.PgConfigTestContainer;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.testcontainers.junit.jupiter.Container;
import org.testcontainers.junit.jupiter.Testcontainers;
import java.util.Optional;
/**
* @since 1.4
*/
@Testcontainers(disabledWithoutDocker = true)
class PgsqlWorkspaceRepositoryTest {
@Container static PgConfigTestContainer<?> container = new PgConfigTestContainer<>();
PgsqlWorkspaceRepository repo;
@BeforeEach
void setUp() {
container.setUp();
repo = new PgsqlWorkspaceRepository(container.getTemplate());
}
@AfterEach
void tearDown() {
container.tearDown();
}
@Test
void testAdd() {
WorkspaceInfoImpl info = new WorkspaceInfoImpl();
info.setId("ws1");
info.setName("ws1");
repo.add(info);
Optional<WorkspaceInfo> found = repo.findById(info.getId(), repo.getContentType());
assertThat(found).isPresent();
}
}

View File

@ -0,0 +1,44 @@
/*
* /* (c) 2014 Open Source Geospatial Foundation - all rights reserved (c) 2001 - 2013 OpenPlans
* This code is licensed under the GPL 2.0 license, available at the root application directory.
*/
package org.geoserver.cloud.backend.pgconfig.config;
import org.geoserver.catalog.Catalog;
import org.geoserver.cloud.backend.pgconfig.PgsqlBackendBuilder;
import org.geoserver.cloud.backend.pgconfig.support.PgConfigTestContainer;
import org.geoserver.config.GeoServer;
import org.geoserver.config.GeoServerConfigConformanceTest;
import org.geoserver.config.plugin.GeoServerImpl;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.testcontainers.junit.jupiter.Container;
import org.testcontainers.junit.jupiter.Testcontainers;
/**
* @since 1.4
*/
@Testcontainers(disabledWithoutDocker = true)
class PgsqlConfigRepositoryConformanceTest extends GeoServerConfigConformanceTest {
@Container static PgConfigTestContainer<?> container = new PgConfigTestContainer<>();
@Override
@BeforeEach
public void setUp() throws Exception {
container.setUp();
super.setUp();
}
@AfterEach
void cleanDb() throws Exception {
container.tearDown();
}
protected @Override GeoServer createGeoServer() {
PgsqlBackendBuilder builder = new PgsqlBackendBuilder(container.getDataSource());
Catalog catalog = builder.createCatalog();
GeoServerImpl gs = builder.createGeoServer(catalog);
return gs;
}
}

View File

@ -0,0 +1,51 @@
/*
* (c) 2023 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.backend.pgconfig.config;
import org.geoserver.cloud.backend.pgconfig.support.PgConfigTestContainer;
import org.geoserver.config.GeoServer;
import org.geoserver.config.plugin.GeoServerImpl;
import org.geoserver.platform.config.UpdateSequence;
import org.geoserver.platform.config.UpdateSequenceConformanceTest;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.testcontainers.junit.jupiter.Container;
import org.testcontainers.junit.jupiter.Testcontainers;
/**
* @since 1.4
*/
@Testcontainers(disabledWithoutDocker = true)
class PgsqlUpdateSequenceTest implements UpdateSequenceConformanceTest {
@Container static PgConfigTestContainer<?> container = new PgConfigTestContainer<>();
private UpdateSequence sequence;
private PgsqlGeoServerFacade facade;
private GeoServer geoserver;
@BeforeEach
public void init() throws Exception {
container.setUp();
facade = new PgsqlGeoServerFacade(container.getTemplate());
geoserver = new GeoServerImpl(facade);
sequence = new PgsqlUpdateSequence(container.getDataSource(), facade);
}
@AfterEach
void cleanDb() throws Exception {
container.tearDown();
}
@Override
public UpdateSequence getUpdataSequence() {
return sequence;
}
@Override
public GeoServer getGeoSever() {
return geoserver;
}
}

View File

@ -2,17 +2,15 @@
* (c) 2023 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.backend.pgsql.resource;
package org.geoserver.cloud.backend.pgconfig.resource;
import com.zaxxer.hikari.HikariConfig;
import com.zaxxer.hikari.HikariDataSource;
import org.geoserver.cloud.config.catalog.backend.pgsql.PgsqlDatabaseMigrations;
import org.geoserver.cloud.backend.pgconfig.support.PgConfigTestContainer;
import org.geoserver.platform.resource.Paths;
import org.geoserver.platform.resource.Resource;
import org.geoserver.platform.resource.Resource.Type;
import org.geoserver.platform.resource.ResourceTheoryTest;
import org.junit.After;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.ClassRule;
@ -27,47 +25,24 @@ import org.springframework.integration.jdbc.lock.JdbcLockRegistry;
import org.springframework.integration.jdbc.lock.LockRepository;
import org.springframework.integration.support.locks.LockRegistry;
import org.springframework.jdbc.core.JdbcTemplate;
import org.testcontainers.containers.PostgreSQLContainer;
import java.util.Arrays;
import java.util.Objects;
import javax.sql.DataSource;
/**
* Note by inheriting from {@link ResourceTheoryTest}, this is a Junit 4 test class and must be
* {@code public}
*/
@RunWith(Theories.class)
class PgsqlResourceTest extends ResourceTheoryTest {
public class PgsqlResourceTest extends ResourceTheoryTest {
public @ClassRule static PostgreSQLContainer<?> container =
new PostgreSQLContainer<>("postgres:15");
static final String schema = "testschema";
static PgsqlDatabaseMigrations databaseMigrations;
static DataSource dataSource;
public @ClassRule static PgConfigTestContainer<?> container = new PgConfigTestContainer<>();
public @Rule TemporaryFolder cacheDir = new TemporaryFolder();
private PgsqlResourceStore store;
public static @BeforeClass void createDataSource() throws Exception {
String url = container.getJdbcUrl();
String username = container.getUsername();
String password = container.getPassword();
String driverClassName = container.getDriverClassName();
HikariConfig hikariConfig = new HikariConfig();
hikariConfig.setJdbcUrl(url);
hikariConfig.setPassword(password);
hikariConfig.setUsername(username);
hikariConfig.setDriverClassName(driverClassName);
hikariConfig.setSchema(schema);
dataSource = new HikariDataSource(hikariConfig);
databaseMigrations =
new PgsqlDatabaseMigrations()
.setSchema(schema)
.setDataSource(dataSource)
.setCleanDisabled(false);
databaseMigrations.migrate();
}
@DataPoints
public static String[] testPaths() {
return new String[] {
@ -83,19 +58,30 @@ class PgsqlResourceTest extends ResourceTheoryTest {
};
}
@After
public void cleanDb() throws Exception {
new JdbcTemplate(dataSource).update("DELETE FROM resourcestore WHERE parentid IS NOT NULL");
@BeforeClass
public static void onetimeSetUp() {
container.setUp();
}
@AfterClass
public static void oneTimeTeardown() {
container.tearDown();
}
@Before
public void setUp() throws Exception {
JdbcTemplate template = new JdbcTemplate(dataSource);
JdbcTemplate template = container.getTemplate();
PgsqlLockProvider lockProvider = new PgsqlLockProvider(pgsqlLockRegistry());
store = new PgsqlResourceStore(cacheDir.getRoot().toPath(), template, lockProvider);
setupTestData(template);
}
@After
public void cleanDb() throws Exception {
DataSource dataSource = container.getDataSource();
new JdbcTemplate(dataSource).update("DELETE FROM resourcestore WHERE parentid IS NOT NULL");
}
private void setupTestData(JdbcTemplate template) throws Exception {
for (String path : testPaths()) {
boolean undef = Paths.name(path).contains("Undef");
@ -111,9 +97,9 @@ class PgsqlResourceTest extends ResourceTheoryTest {
byte[] contents = dir ? null : path.getBytes("UTF-8");
String sql =
"""
INSERT INTO resourcestore (parentid, name, "type", content)
VALUES (?, ?, ?, ?)
""";
INSERT INTO resourcestore (parentid, name, "type", content)
VALUES (?, ?, ?, ?)
""";
template.update(sql, parentId, name, type.toString(), contents);
}
}
@ -127,6 +113,7 @@ class PgsqlResourceTest extends ResourceTheoryTest {
}
LockRepository pgsqlLockRepository() {
DataSource dataSource = container.getDataSource();
DefaultLockRepository lockRepository =
new DefaultLockRepository(dataSource, "test-instance");
// override default table prefix "INT" by "RESOURCE_" (matching table definition

View File

@ -0,0 +1,107 @@
/*
* (c) 2023 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.backend.pgconfig.support;
import com.zaxxer.hikari.HikariConfig;
import com.zaxxer.hikari.HikariDataSource;
import lombok.Getter;
import lombok.SneakyThrows;
import org.geoserver.cloud.config.catalog.backend.pgconfig.PgsqlDatabaseMigrations;
import org.geoserver.cloud.config.jndi.SimpleJNDIStaticContextInitializer;
import org.geoserver.cloud.config.jndidatasource.JNDIDataSourceAutoConfiguration;
import org.springframework.boot.autoconfigure.AutoConfigurations;
import org.springframework.boot.test.context.runner.AbstractApplicationContextRunner;
import org.springframework.jdbc.core.JdbcTemplate;
import org.testcontainers.Testcontainers;
import org.testcontainers.containers.PostgreSQLContainer;
import javax.sql.DataSource;
/**
* A {@link Testcontainers test container} based on {@link PostgreSQLContainer} using PostgreSQL 15
* to aid in setting up the {@code DataSource}, {@code JdbcTemplate}, and {@link
* PgsqlDatabaseMigrations Flyway} database migrations for the {@literal pgconfig} catalog backend.
*
* @since 1.6
*/
public class PgConfigTestContainer<SELF extends PostgreSQLContainer<SELF>>
extends PostgreSQLContainer<SELF> {
private @Getter DataSource dataSource;
private @Getter JdbcTemplate template;
private @Getter String schema = "pgconfigtest";
private @Getter PgsqlDatabaseMigrations databaseMigrations;
public PgConfigTestContainer() {
super("postgres:15");
}
@SneakyThrows(Exception.class)
public PgConfigTestContainer<SELF> setUp() {
String url = getJdbcUrl();
String username = getUsername();
String password = getPassword();
String driverClassName = getDriverClassName();
HikariConfig hikariConfig = new HikariConfig();
hikariConfig.setJdbcUrl(url);
hikariConfig.setPassword(password);
hikariConfig.setUsername(username);
hikariConfig.setDriverClassName(driverClassName);
hikariConfig.setSchema(schema);
dataSource = new HikariDataSource(hikariConfig);
template = new JdbcTemplate(dataSource);
databaseMigrations =
new PgsqlDatabaseMigrations()
.setSchema(schema)
.setDataSource(dataSource)
.setCleanDisabled(false);
databaseMigrations.migrate();
return this;
}
public void tearDown() {
if (null != databaseMigrations) databaseMigrations.clean();
if (null != dataSource) ((HikariDataSource) dataSource).close();
}
@SuppressWarnings("unchecked")
public <R extends AbstractApplicationContextRunner<?, ?, ?>> R withJdbcUrlConfig(R runner) {
String url = getJdbcUrl();
String username = getUsername();
String password = getPassword();
return (R)
runner.withPropertyValues( //
"geoserver.backend.pgconfig.enabled=true", //
"geoserver.backend.pgconfig.datasource.url=" + url, //
"geoserver.backend.pgconfig.datasource.username=" + username, //
"geoserver.backend.pgconfig.datasource.password=" + password //
);
}
@SuppressWarnings("unchecked")
public <R extends AbstractApplicationContextRunner<?, ?, ?>> R withJndiConfig(R runner) {
String url = getJdbcUrl();
String username = getUsername();
String password = getPassword();
return (R)
runner
// enable simplejndi
.withInitializer(new SimpleJNDIStaticContextInitializer())
.withConfiguration(
AutoConfigurations.of(JNDIDataSourceAutoConfiguration.class))
.withPropertyValues(
"geoserver.backend.pgconfig.enabled: true", //
// java:comp/env/jdbc/testdb config properties
"jndi.datasources.testdb.enabled: true", //
"jndi.datasources.testdb.url: " + url,
"jndi.datasources.testdb.username: " + username, //
"jndi.datasources.testdb.password: " + password, //
// pgsql backend datasource config using jndi
"geoserver.backend.pgconfig.datasource.jndi-name: java:comp/env/jdbc/testdb");
}
}

View File

@ -15,6 +15,7 @@
<logger name="com.zaxxer.hikari.HikariDataSource" level="WARN"/>
<logger name="org.geoserver.cloud.autoconfigure.catalog.backend" level="DEBUG"/>
<logger name="org.geoserver.cloud.config.catalog.backend.pgsql" level="WARN"/>
<logger name="org.geoserver.cloud.backend.pgsql.gwc.repository" level="INFO"/>
<logger name="org.geoserver.catalog.impl" level="OFF"/>
</configuration>

View File

@ -1,22 +0,0 @@
/*
* (c) 2023 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.backend.pgsql.gwc;
import org.springframework.jdbc.core.RowMapper;
import java.sql.ResultSet;
import java.sql.SQLException;
/**
* @since 1.4
*/
public class GeoServerTileLayerInfoRowMapper implements RowMapper<PgsqlTileLayerInfo> {
@Override
public PgsqlTileLayerInfo mapRow(ResultSet rs, int rowNum) throws SQLException {
// TODO Auto-generated method stub
return null;
}
}

View File

@ -1,221 +0,0 @@
/*
* (c) 2023 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.backend.pgsql.gwc;
import lombok.NonNull;
import lombok.RequiredArgsConstructor;
import org.geoserver.catalog.WorkspaceInfo;
import org.geoserver.gwc.layer.GeoServerTileLayerInfo;
import org.geoserver.gwc.layer.TileLayerCatalog;
import org.geoserver.gwc.layer.TileLayerCatalogListener;
import org.geoserver.ows.LocalWorkspace;
import org.springframework.jdbc.core.JdbcTemplate;
import java.util.Set;
import java.util.stream.Collectors;
/**
* @since 1.4
*/
@RequiredArgsConstructor
public class PgsqlTileLayerCatalog implements TileLayerCatalog {
private final @NonNull JdbcTemplate template;
private GeoServerTileLayerInfoRowMapper rowMapper;
@Override
public void addListener(TileLayerCatalogListener listener) {
throw new UnsupportedOperationException("implement");
}
@Override
public boolean exists(String layerId) {
return template.queryForObject(
"""
SELECT exists(id) FROM tile_layer WHERE id = ?
""",
(rs, rn) -> rs.getBoolean(1),
layerId);
}
@Override
public Set<String> getLayerIds() {
return template.queryForStream(
"""
SELECT id FROM tile_layers
""",
(rs, rn) -> rs.getString(1))
.collect(Collectors.toSet());
}
@Override
public Set<String> getLayerNames() {
return template.queryForStream(
"""
SELECT name FROM tile_layers ORDER BY name
""",
(rs, rn) -> rs.getString(1))
.collect(Collectors.toSet());
}
@Override
public String getLayerId(String layerName) {
final WorkspaceInfo ws = LocalWorkspace.get();
final String workspace = workspace(layerName);
final String name = name(layerName);
if (ws != null && !layerName.startsWith(ws.getName() + ":")) {
throw new IllegalArgumentException(
"Local workspace is %s, but requested layer %s"
.formatted(ws.getName(), layerName));
}
if (null == workspace) {
return template.queryForObject(
"""
SELECT id FROM tile_layers WHERE workspace IS NULL AND name = ?
""",
(rs, rn) -> rs.getString(1),
name);
}
return template.queryForObject(
"""
SELECT id FROM tile_layers WHERE workspace = ? AND name = ?
""",
(rs, rn) -> rs.getString(1),
workspace,
name);
}
private String name(String layerName) {
return layerName.indexOf(':') == -1
? layerName
: layerName.substring(1 + layerName.indexOf(':'));
}
private String workspace(String layerName) {
return layerName.indexOf(':') == -1 ? null : layerName.substring(0, layerName.indexOf(':'));
}
@Override
public String getLayerName(String layerId) {
return template.queryForObject(
"""
SELECT workspace, name FROM tile_layers WHERE id = ?
""",
(rs, rn) -> {
String ws = rs.getString(1);
String name = rs.getString(2);
return ws == null ? name : (ws + ":" + name);
},
layerId);
}
@Override
public PgsqlTileLayerInfo getLayerById(String id) {
return template.queryForObject(
"""
SELECT * FROM tile_layers WHERE id = ?
""",
rowMapper,
id);
}
@Override
public PgsqlTileLayerInfo getLayerByName(String layerName) {
final WorkspaceInfo ws = LocalWorkspace.get();
final String workspace = workspace(layerName);
final String name = name(layerName);
if (ws != null && !layerName.startsWith(ws.getName() + ":")) {
throw new IllegalArgumentException(
"Local workspace is %s, but requested layer %s"
.formatted(ws.getName(), layerName));
}
if (null == workspace) {
return template.queryForObject(
"""
SELECT * FROM tile_layers WHERE workspace IS NULL AND name = ?
""",
rowMapper,
workspace,
name);
}
return template.queryForObject(
"""
SELECT * FROM tile_layers WHERE workspace = ? AND name = ?
""",
rowMapper,
workspace,
name);
}
@Override
public PgsqlTileLayerInfo delete(String tileLayerId) {
PgsqlTileLayerInfo currValue = getLayerById(tileLayerId);
if (null != currValue) {
int updated =
template.update(
"""
DELETE FROM tile_layer WHERE id = ?
""",
tileLayerId);
if (0 == updated) currValue = null;
}
return currValue;
}
@Override
public PgsqlTileLayerInfo save(GeoServerTileLayerInfo newValue) {
// TODO: make sure name clashes throw a sql exception
// if (oldValue == null) {
// final String duplicateNameId = layersByName.get(newValue.getName());
// if (null != duplicateNameId) {
// throw new IllegalArgumentException(
// "TileLayer with same name already exists: "
// + newValue.getName()
// + ": <"
// + duplicateNameId
// + ">");
// }
// }
final String encoded = encode(newValue);
final String tileLayerId = newValue.getId();
int updated =
template.update(
"""
UPDATE tile_layer SET info = to_json(?::json) WHERE id = ?
""",
tileLayerId,
encoded);
if (1 == updated) return getLayerById(tileLayerId);
throw new IllegalArgumentException("TileLayer %s does not exist".formatted(tileLayerId));
}
/**
* @param newValue
* @return
*/
private String encode(GeoServerTileLayerInfo newValue) {
throw new UnsupportedOperationException();
}
@Override
public void initialize() {
throw new UnsupportedOperationException("implement");
}
@Override
public void reset() {
throw new UnsupportedOperationException("implement");
}
@Override
public String getPersistenceLocation() {
throw new UnsupportedOperationException("implement");
}
}

View File

@ -1,26 +0,0 @@
/*
* (c) 2023 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.backend.pgsql.gwc;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.Setter;
import org.geoserver.gwc.layer.GeoServerTileLayerInfoImpl;
/**
* @since 1.4
*/
@EqualsAndHashCode(callSuper = true)
@SuppressWarnings("serial")
public class PgsqlTileLayerInfo extends GeoServerTileLayerInfoImpl {
@Getter @Setter private String workspaceId;
@Override
public PgsqlTileLayerInfo clone() {
return (PgsqlTileLayerInfo) super.clone();
}
}

View File

@ -1,5 +0,0 @@
# Auto Configure
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.geoserver.cloud.autoconfigure.catalog.backend.pgsql.PgsqlDataSourceAutoConfiguration,\
org.geoserver.cloud.autoconfigure.catalog.backend.pgsql.PgsqlMigrationAutoConfiguration,\
org.geoserver.cloud.autoconfigure.catalog.backend.pgsql.PgsqlBackendAutoConfiguration

View File

@ -1,88 +0,0 @@
/*
* (c) 2023 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.backend.pgsql.catalog;
import com.zaxxer.hikari.HikariConfig;
import com.zaxxer.hikari.HikariDataSource;
import org.geoserver.catalog.impl.CatalogImpl;
import org.geoserver.catalog.plugin.CatalogConformanceTest;
import org.geoserver.cloud.backend.pgsql.PgsqlBackendBuilder;
import org.geoserver.cloud.config.catalog.backend.pgsql.PgsqlDatabaseMigrations;
import org.geotools.util.logging.Logging;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Disabled;
import org.testcontainers.containers.PostgreSQLContainer;
import org.testcontainers.junit.jupiter.Container;
import org.testcontainers.junit.jupiter.Testcontainers;
import javax.sql.DataSource;
/**
* @since 1.4
*/
@Testcontainers(disabledWithoutDocker = true)
class PgsqlCatalogBackendConformanceTest extends CatalogConformanceTest {
@Container static PostgreSQLContainer<?> container = new PostgreSQLContainer<>("postgres:15");
static DataSource dataSource;
static final String schema = "testschema";
static PgsqlDatabaseMigrations databaseMigrations;
@Disabled(
"""
revisit, seems to be just a problem of ordering or equals with the \
returned ft/ft2 where mockito is not throwing the expected exception
""")
@Override
public void testSaveDataStoreRollbacksBothStoreAndResources() throws Exception {}
static @BeforeAll void createDataSource() throws Exception {
String url = container.getJdbcUrl();
String username = container.getUsername();
String password = container.getPassword();
String driverClassName = container.getDriverClassName();
HikariConfig hikariConfig = new HikariConfig();
hikariConfig.setJdbcUrl(url);
hikariConfig.setPassword(password);
hikariConfig.setUsername(username);
hikariConfig.setDriverClassName(driverClassName);
hikariConfig.setSchema(schema);
dataSource = new HikariDataSource(hikariConfig);
databaseMigrations =
new PgsqlDatabaseMigrations()
.setSchema(schema)
.setDataSource(dataSource)
.setCleanDisabled(false);
try {
Logging.ALL.setLoggerFactory("org.geotools.util.logging.CommonsLoggerFactory");
} catch (ClassNotFoundException e) {
throw new IllegalStateException(e);
}
}
@Override
@BeforeEach
public void setUp() throws Exception {
databaseMigrations.migrate();
super.setUp();
}
@AfterEach
void cleanDb() throws Exception {
databaseMigrations.clean();
}
@Override
protected CatalogImpl createCatalog() {
return new PgsqlBackendBuilder(dataSource).createCatalog();
}
}

View File

@ -1,69 +0,0 @@
/*
* (c) 2023 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.backend.pgsql.catalog.repository;
import static org.assertj.core.api.Assertions.assertThat;
import com.zaxxer.hikari.HikariConfig;
import com.zaxxer.hikari.HikariDataSource;
import org.geoserver.catalog.WorkspaceInfo;
import org.geoserver.catalog.impl.WorkspaceInfoImpl;
import org.geoserver.cloud.config.catalog.backend.pgsql.PgsqlDatabaseMigrations;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.jdbc.core.JdbcTemplate;
import org.testcontainers.containers.PostgreSQLContainer;
import org.testcontainers.junit.jupiter.Container;
import org.testcontainers.junit.jupiter.Testcontainers;
import java.util.Optional;
import javax.sql.DataSource;
/**
* @since 1.4
*/
@Testcontainers(disabledWithoutDocker = true)
class PgsqlWorkspaceRepositoryTest {
@Container static PostgreSQLContainer<?> container = new PostgreSQLContainer<>("postgres:15");
static DataSource dataSource;
PgsqlWorkspaceRepository repo;
static @BeforeAll void createDataSource() throws Exception {
String url = container.getJdbcUrl();
String username = container.getUsername();
String password = container.getPassword();
String driverClassName = container.getDriverClassName();
HikariConfig hikariConfig = new HikariConfig();
hikariConfig.setJdbcUrl(url);
hikariConfig.setPassword(password);
hikariConfig.setUsername(username);
hikariConfig.setDriverClassName(driverClassName);
dataSource = new HikariDataSource(hikariConfig);
new PgsqlDatabaseMigrations().setDataSource(dataSource).migrate();
}
@BeforeEach
void setUp() {
repo = new PgsqlWorkspaceRepository(new JdbcTemplate(dataSource));
}
@Test
void testAdd() {
WorkspaceInfoImpl info = new WorkspaceInfoImpl();
info.setId("ws1");
info.setName("ws1");
repo.add(info);
Optional<WorkspaceInfo> found = repo.findById(info.getId(), repo.getContentType());
assertThat(found).isPresent();
}
}

View File

@ -1,76 +0,0 @@
/*
* /* (c) 2014 Open Source Geospatial Foundation - all rights reserved (c) 2001 - 2013 OpenPlans
* This code is licensed under the GPL 2.0 license, available at the root application directory.
*/
package org.geoserver.cloud.backend.pgsql.config;
import com.zaxxer.hikari.HikariConfig;
import com.zaxxer.hikari.HikariDataSource;
import org.geoserver.catalog.Catalog;
import org.geoserver.cloud.backend.pgsql.PgsqlBackendBuilder;
import org.geoserver.cloud.config.catalog.backend.pgsql.PgsqlDatabaseMigrations;
import org.geoserver.config.GeoServer;
import org.geoserver.config.GeoServerConfigConformanceTest;
import org.geoserver.config.plugin.GeoServerImpl;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.BeforeEach;
import org.testcontainers.containers.PostgreSQLContainer;
import org.testcontainers.junit.jupiter.Container;
import org.testcontainers.junit.jupiter.Testcontainers;
import javax.sql.DataSource;
/**
* @since 1.4
*/
@Testcontainers(disabledWithoutDocker = true)
class PgsqlConfigRepositoryConformanceTest extends GeoServerConfigConformanceTest {
@Container static PostgreSQLContainer<?> container = new PostgreSQLContainer<>("postgres:15");
static DataSource dataSource;
static final String schema = "testschema";
static PgsqlDatabaseMigrations databaseMigrations;
static @BeforeAll void createDataSource() throws Exception {
String url = container.getJdbcUrl();
String username = container.getUsername();
String password = container.getPassword();
String driverClassName = container.getDriverClassName();
HikariConfig hikariConfig = new HikariConfig();
hikariConfig.setJdbcUrl(url);
hikariConfig.setPassword(password);
hikariConfig.setUsername(username);
hikariConfig.setDriverClassName(driverClassName);
hikariConfig.setSchema(schema);
dataSource = new HikariDataSource(hikariConfig);
databaseMigrations =
new PgsqlDatabaseMigrations()
.setSchema(schema)
.setDataSource(dataSource)
.setCleanDisabled(false);
}
@Override
@BeforeEach
public void setUp() throws Exception {
databaseMigrations.migrate();
super.setUp();
}
@AfterEach
void cleanDb() throws Exception {
databaseMigrations.clean();
}
protected @Override GeoServer createGeoServer() {
PgsqlBackendBuilder builder = new PgsqlBackendBuilder(dataSource);
Catalog catalog = builder.createCatalog();
GeoServerImpl gs = builder.createGeoServer(catalog);
return gs;
}
}

View File

@ -1,83 +0,0 @@
/*
* (c) 2023 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.backend.pgsql.config;
import com.zaxxer.hikari.HikariConfig;
import com.zaxxer.hikari.HikariDataSource;
import org.geoserver.cloud.config.catalog.backend.pgsql.PgsqlDatabaseMigrations;
import org.geoserver.config.GeoServer;
import org.geoserver.config.plugin.GeoServerImpl;
import org.geoserver.platform.config.UpdateSequence;
import org.geoserver.platform.config.UpdateSequenceConformanceTest;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.BeforeEach;
import org.springframework.jdbc.core.JdbcTemplate;
import org.testcontainers.containers.PostgreSQLContainer;
import org.testcontainers.junit.jupiter.Container;
import org.testcontainers.junit.jupiter.Testcontainers;
import javax.sql.DataSource;
/**
* @since 1.4
*/
@Testcontainers(disabledWithoutDocker = true)
class PgsqlUpdateSequenceTest implements UpdateSequenceConformanceTest {
@Container static PostgreSQLContainer<?> container = new PostgreSQLContainer<>("postgres:15");
static DataSource dataSource;
static final String schema = "testschema";
static PgsqlDatabaseMigrations databaseMigrations;
static @BeforeAll void createDataSource() throws Exception {
String url = container.getJdbcUrl();
String username = container.getUsername();
String password = container.getPassword();
String driverClassName = container.getDriverClassName();
HikariConfig hikariConfig = new HikariConfig();
hikariConfig.setJdbcUrl(url);
hikariConfig.setPassword(password);
hikariConfig.setUsername(username);
hikariConfig.setDriverClassName(driverClassName);
hikariConfig.setSchema(schema);
dataSource = new HikariDataSource(hikariConfig);
databaseMigrations =
new PgsqlDatabaseMigrations()
.setSchema(schema)
.setDataSource(dataSource)
.setCleanDisabled(false);
}
private UpdateSequence sequence;
private PgsqlGeoServerFacade facade;
private GeoServer geoserver;
@BeforeEach
public void init() throws Exception {
databaseMigrations.migrate();
facade = new PgsqlGeoServerFacade(new JdbcTemplate(dataSource));
geoserver = new GeoServerImpl(facade);
sequence = new PgsqlUpdateSequence(dataSource, facade);
}
@AfterEach
void cleanDb() throws Exception {
databaseMigrations.clean();
}
@Override
public UpdateSequence getUpdataSequence() {
return sequence;
}
@Override
public GeoServer getGeoSever() {
return geoserver;
}
}

View File

@ -13,8 +13,8 @@
<modules>
<module>common</module>
<module>datadir</module>
<module>pgconfig</module>
<module>jdbcconfig</module>
<module>pgsql</module>
</modules>
<dependencies>
<dependency>

View File

@ -135,7 +135,7 @@ public class CatalogFaker {
return new CatalogFaker(catalog, geoserver, locale);
}
private Catalog catalog() {
public Catalog catalog() {
return catalog.get();
}
@ -143,6 +143,10 @@ public class CatalogFaker {
return catalog().getFactory();
}
public LayerGroupInfo layerGroupInfo(WorkspaceInfo workspace) {
return layerGroupInfo(id(), workspace, name(), null, null);
}
public LayerGroupInfo layerGroupInfo(
String id, WorkspaceInfo workspace, String name, PublishedInfo layer, StyleInfo style) {
// not using factory cause SecuredCatalog would return SecuredLayerGroupInfo which has no id
@ -151,8 +155,8 @@ public class CatalogFaker {
OwsUtils.set(lg, "id", id);
lg.setName(name);
lg.setWorkspace(workspace);
lg.getLayers().add(layer);
lg.getStyles().add(style);
if (layer != null) lg.getLayers().add(layer);
if (style != null) lg.getStyles().add(style);
OwsUtils.resolveCollections(lg);
return lg;
}
@ -281,12 +285,16 @@ public class CatalogFaker {
}
public FeatureTypeInfo featureTypeInfo(DataStoreInfo ds) {
String name = name();
return featureTypeInfo(ds, name);
}
public FeatureTypeInfo featureTypeInfo(DataStoreInfo ds, String name) {
String prefix = ds.getWorkspace().getName();
NamespaceInfo ns = catalog().getNamespaceByPrefix(prefix);
Objects.requireNonNull(ns, "Namespace " + prefix + " does not exist");
String id = "FeatureType." + id();
String name = name();
String id = "FeatureType." + name + "." + id();
String abstracT = faker().company().bs();
String description = faker().company().buzzword();
boolean enabled = true;

View File

@ -20,7 +20,7 @@
</dependency>
<dependency>
<groupId>org.geoserver.cloud.catalog.backend</groupId>
<artifactId>gs-cloud-catalog-backend-pgsql</artifactId>
<artifactId>gs-cloud-catalog-backend-pgconfig</artifactId>
</dependency>
<dependency>
<groupId>org.geoserver.cloud.catalog</groupId>