From 6562aea28a35235207a1e23a920f14ab5958c198 Mon Sep 17 00:00:00 2001 From: George Brownbridge Date: Thu, 6 Nov 2025 16:42:01 +0000 Subject: [PATCH 1/4] external-postgres-endpoints: Bumped the version number. --- stack-clients/docker-compose.yml | 2 +- stack-clients/pom.xml | 2 +- stack-data-uploader/docker-compose.yml | 2 +- stack-data-uploader/pom.xml | 4 ++-- stack-manager/docker-compose.yml | 2 +- stack-manager/pom.xml | 4 ++-- 6 files changed, 8 insertions(+), 8 deletions(-) diff --git a/stack-clients/docker-compose.yml b/stack-clients/docker-compose.yml index 67af642a..b1d0022c 100644 --- a/stack-clients/docker-compose.yml +++ b/stack-clients/docker-compose.yml @@ -1,6 +1,6 @@ services: stack-client: - image: ghcr.io/theworldavatar/stack-client${IMAGE_SUFFIX}:1.54.1 + image: ghcr.io/theworldavatar/stack-client${IMAGE_SUFFIX}:1.55.0-external-postgres-SNAPSHOT secrets: - blazegraph_password - postgis_password diff --git a/stack-clients/pom.xml b/stack-clients/pom.xml index 1f122256..53bf0983 100644 --- a/stack-clients/pom.xml +++ b/stack-clients/pom.xml @@ -7,7 +7,7 @@ com.cmclinnovations stack-clients - 1.54.1 + 1.55.0-external-postgres-SNAPSHOT Stack Clients https://theworldavatar.io diff --git a/stack-data-uploader/docker-compose.yml b/stack-data-uploader/docker-compose.yml index e07d9ef3..f162a5cf 100644 --- a/stack-data-uploader/docker-compose.yml +++ b/stack-data-uploader/docker-compose.yml @@ -1,6 +1,6 @@ services: stack-data-uploader: - image: ghcr.io/theworldavatar/stack-data-uploader${IMAGE_SUFFIX}:1.54.1 + image: ghcr.io/theworldavatar/stack-data-uploader${IMAGE_SUFFIX}:1.55.0-external-postgres-SNAPSHOT secrets: - blazegraph_password - postgis_password diff --git a/stack-data-uploader/pom.xml b/stack-data-uploader/pom.xml index 85c6c570..151044a0 100644 --- a/stack-data-uploader/pom.xml +++ b/stack-data-uploader/pom.xml @@ -7,7 +7,7 @@ com.cmclinnovations stack-data-uploader - 1.54.1 + 1.55.0-external-postgres-SNAPSHOT Stack Data Uploader https://theworldavatar.io @@ -38,7 +38,7 @@ com.cmclinnovations stack-clients - 1.54.1 + 1.55.0-external-postgres-SNAPSHOT diff --git a/stack-manager/docker-compose.yml b/stack-manager/docker-compose.yml index 6f095bd3..590755e8 100644 --- a/stack-manager/docker-compose.yml +++ b/stack-manager/docker-compose.yml @@ -1,6 +1,6 @@ services: stack-manager: - image: ghcr.io/theworldavatar/stack-manager${IMAGE_SUFFIX}:1.54.1 + image: ghcr.io/theworldavatar/stack-manager${IMAGE_SUFFIX}:1.55.0-external-postgres-SNAPSHOT environment: EXTERNAL_PORT: "${EXTERNAL_PORT-3838}" STACK_BASE_DIR: "${STACK_BASE_DIR}" diff --git a/stack-manager/pom.xml b/stack-manager/pom.xml index 74ae3bd8..59a7ec2e 100644 --- a/stack-manager/pom.xml +++ b/stack-manager/pom.xml @@ -7,7 +7,7 @@ com.cmclinnovations stack-manager - 1.54.1 + 1.55.0-external-postgres-SNAPSHOT Stack Manager https://theworldavatar.io @@ -38,7 +38,7 @@ com.cmclinnovations stack-clients - 1.54.1 + 1.55.0-external-postgres-SNAPSHOT From 3981bf55837c430f3b30cd1d1e6124240716fb28 Mon Sep 17 00:00:00 2001 From: George Brownbridge Date: Mon, 10 Nov 2025 09:38:14 +0000 Subject: [PATCH 2/4] external-postgres-endpoints: Minor changes to remove linter warnings. --- .../stack/clients/core/datasets/RML.java | 1 - .../stack/clients/core/datasets/XtoCityDB.java | 12 ++++++------ .../stack/clients/gdal/CommonOptions.java | 17 +++++++++++------ .../stack/clients/gdal/GDALClient.java | 5 ++--- .../stack/clients/gdal/GDALOptions.java | 2 +- .../stack/clients/utils/AliasMap.java | 2 +- 6 files changed, 21 insertions(+), 18 deletions(-) diff --git a/stack-clients/src/main/java/com/cmclinnovations/stack/clients/core/datasets/RML.java b/stack-clients/src/main/java/com/cmclinnovations/stack/clients/core/datasets/RML.java index a9ca70f6..cb6deb73 100644 --- a/stack-clients/src/main/java/com/cmclinnovations/stack/clients/core/datasets/RML.java +++ b/stack-clients/src/main/java/com/cmclinnovations/stack/clients/core/datasets/RML.java @@ -1,7 +1,6 @@ package com.cmclinnovations.stack.clients.core.datasets; import java.nio.file.Path; -import java.util.Map; import com.cmclinnovations.stack.clients.rml.RmlMapperClient; diff --git a/stack-clients/src/main/java/com/cmclinnovations/stack/clients/core/datasets/XtoCityDB.java b/stack-clients/src/main/java/com/cmclinnovations/stack/clients/core/datasets/XtoCityDB.java index f5045369..9817aef6 100644 --- a/stack-clients/src/main/java/com/cmclinnovations/stack/clients/core/datasets/XtoCityDB.java +++ b/stack-clients/src/main/java/com/cmclinnovations/stack/clients/core/datasets/XtoCityDB.java @@ -34,12 +34,12 @@ protected void loadDataInternal(Path dataSubsetDir, String database, String base GDALClient.getInstance() .uploadVectorFilesToPostGIS(database, getSchema(), getTable(), dataSubsetDir.toString(), ogr2ogrOptions, false); - CityDBClient.getInstance() - .updateDatabase(database, getSridIn()); - CityDBClient.getInstance().preparePGforCityDB(database, getTable(), JsonHelper.handleFileValues(preprocessSql), - minArea, columnMap); - CityDBClient.getInstance().populateCityDBbySQL(database, lineage, columnMap); - CityDBClient.getInstance().addIRIs(database, baseIRI); + CityDBClient instance = CityDBClient.getInstance(); + instance.updateDatabase(database, getSridIn()); + instance.preparePGforCityDB(database, getTable(), JsonHelper.handleFileValues(preprocessSql), minArea, + columnMap); + instance.populateCityDBbySQL(database, lineage, columnMap); + instance.addIRIs(database, baseIRI); } @Override diff --git a/stack-clients/src/main/java/com/cmclinnovations/stack/clients/gdal/CommonOptions.java b/stack-clients/src/main/java/com/cmclinnovations/stack/clients/gdal/CommonOptions.java index 532ec608..0bcba84c 100644 --- a/stack-clients/src/main/java/com/cmclinnovations/stack/clients/gdal/CommonOptions.java +++ b/stack-clients/src/main/java/com/cmclinnovations/stack/clients/gdal/CommonOptions.java @@ -39,13 +39,18 @@ protected CommonOptions(String command) { this.command = command; } + @SuppressWarnings("unchecked") + protected final T self() { + return (T) this; + } + public final String getSridIn() { return sridIn; } public final T setSridIn(String sridIn) { this.sridIn = sridIn; - return (T) this; + return self(); } public final String getSridOut() { @@ -54,27 +59,27 @@ public final String getSridOut() { public final T setSridOut(String sridOut) { this.sridOut = sridOut; - return (T) this; + return self(); } public final T addInputDatasetOpenOption(String name, String value) { inputDatasetOpenOptions.put(name, value); - return (T) this; + return self(); } public final T addOtherOption(String option, String... values) { otherOptions.put(option, new Option(values)); - return (T) this; + return self(); } public final T addConfigOption(String option, String value) { configOptions.put(option, value); - return (T) this; + return self(); } public final T withEnv(String key, String value) { envVars.put(key, value); - return (T) this; + return self(); } public final Map getEnv() { diff --git a/stack-clients/src/main/java/com/cmclinnovations/stack/clients/gdal/GDALClient.java b/stack-clients/src/main/java/com/cmclinnovations/stack/clients/gdal/GDALClient.java index 15af8883..d3793ce0 100644 --- a/stack-clients/src/main/java/com/cmclinnovations/stack/clients/gdal/GDALClient.java +++ b/stack-clients/src/main/java/com/cmclinnovations/stack/clients/gdal/GDALClient.java @@ -250,9 +250,8 @@ private void addCustomCRStoPostGis(String gdalContainerId, String filePath, Stri sridAuthNameArray = newSrid.split(":"); String authName = sridAuthNameArray[0]; String srid = sridAuthNameArray[1]; - PostGISClient.getInstance().addProjectionsToPostgis(databaseName, proj4String, - wktString, - authName, srid); + PostGISClient.getInstance() + .addProjectionsToPostgis(databaseName, proj4String, wktString, authName, srid); GeoServerClient.getInstance().addProjectionsToGeoserver(wktString, srid); } catch (NullPointerException ex) { throw new RuntimeException( diff --git a/stack-clients/src/main/java/com/cmclinnovations/stack/clients/gdal/GDALOptions.java b/stack-clients/src/main/java/com/cmclinnovations/stack/clients/gdal/GDALOptions.java index 082ca278..0030087b 100644 --- a/stack-clients/src/main/java/com/cmclinnovations/stack/clients/gdal/GDALOptions.java +++ b/stack-clients/src/main/java/com/cmclinnovations/stack/clients/gdal/GDALOptions.java @@ -18,7 +18,7 @@ protected GDALOptions(String command) { public final T addCreationOption(String name, String value) { creationOptions.put(name, value); - return (T) this; + return self(); } public final String[] generateCommand(String sourceFormat, String source, String destination, diff --git a/stack-clients/src/main/java/com/cmclinnovations/stack/clients/utils/AliasMap.java b/stack-clients/src/main/java/com/cmclinnovations/stack/clients/utils/AliasMap.java index fd02f3ce..113e4d71 100644 --- a/stack-clients/src/main/java/com/cmclinnovations/stack/clients/utils/AliasMap.java +++ b/stack-clients/src/main/java/com/cmclinnovations/stack/clients/utils/AliasMap.java @@ -28,7 +28,7 @@ public final V get(String... aliases) { } } } - return null; + return (V) null; } @SafeVarargs From 728f8d1291b14e54cf2cf80b5bfdd9375065c267 Mon Sep 17 00:00:00 2001 From: George Brownbridge Date: Mon, 10 Nov 2025 17:24:51 +0000 Subject: [PATCH 3/4] external-postgres-endpoints: Updated several parts of the code to accept a `Database` object rather than just the name of the database. This object optionally contains a `PostGISEndpointConfig` other than the default one. --- .../stack/clients/core/datasets/CityDB.java | 10 ++-- .../core/datasets/DCATUpdateQuery.java | 8 +-- .../stack/clients/core/datasets/Dataset.java | 11 ++-- .../clients/core/datasets/DatasetLoader.java | 19 ++++--- .../clients/core/datasets/DatasetRemover.java | 4 +- .../core/datasets/GeoServerDataSubset.java | 4 +- .../clients/core/datasets/OSMRouting.java | 5 +- .../core/datasets/PostgresDataSubset.java | 12 +++-- .../stack/clients/core/datasets/Raster.java | 3 +- .../stack/clients/core/datasets/Vector.java | 3 +- .../clients/geoserver/GeoServerClient.java | 28 +++++----- .../stack/clients/postgis/Database.java | 54 +++++++++++++++++++ .../stack/clients/postgis/PostGISClient.java | 21 +++++--- .../stack/clients/rdf4j/Rdf4jClient.java | 1 - .../core/datasets/DCATUpdateQueryTest.java | 4 +- .../clients/core/datasets/DatasetBuilder.java | 7 +-- .../clients/core/datasets/DatasetTest.java | 4 +- .../geoserver/GeoServerClientTest.java | 37 +++++++------ .../stack/clients/mocks/MockPostGIS.java | 1 + 19 files changed, 157 insertions(+), 79 deletions(-) create mode 100644 stack-clients/src/main/java/com/cmclinnovations/stack/clients/postgis/Database.java diff --git a/stack-clients/src/main/java/com/cmclinnovations/stack/clients/core/datasets/CityDB.java b/stack-clients/src/main/java/com/cmclinnovations/stack/clients/core/datasets/CityDB.java index d802ea76..efd1d5a6 100644 --- a/stack-clients/src/main/java/com/cmclinnovations/stack/clients/core/datasets/CityDB.java +++ b/stack-clients/src/main/java/com/cmclinnovations/stack/clients/core/datasets/CityDB.java @@ -12,6 +12,7 @@ import com.cmclinnovations.stack.clients.citydb.ImpExpOptions; import com.cmclinnovations.stack.clients.geoserver.GeoServerClient; import com.cmclinnovations.stack.clients.geoserver.GeoServerVectorSettings; +import com.cmclinnovations.stack.clients.postgis.Database; import com.cmclinnovations.stack.clients.postgis.PostGISClient; import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonProperty; @@ -62,18 +63,19 @@ protected void setPreviousFile(Path previousFilePath) { @Override void loadInternal(Dataset parent) { - String database = parent.getDatabase(); + Database database = parent.getDatabase(); + String databaseName = database.getDatabaseName(); super.loadInternal(parent); if (null != previousFile) { logger.info("Exporting data..."); - writeOutPrevious(database); + writeOutPrevious(databaseName); } if (createTile) { logger.info("Creating 3D tiles..."); - createLayer(database); + createLayer(databaseName); } } @@ -140,7 +142,7 @@ public String getSchema() { } @Override - public void createLayers(String workspaceName, String database) { + public void createLayers(String workspaceName, Database database) { logger.info("Publishing to geoserver..."); GeoServerClient.getInstance() .createPostGISLayer(workspaceName, database, getSchema(), getTable(), geoServerSettings); diff --git a/stack-clients/src/main/java/com/cmclinnovations/stack/clients/core/datasets/DCATUpdateQuery.java b/stack-clients/src/main/java/com/cmclinnovations/stack/clients/core/datasets/DCATUpdateQuery.java index 526b2c9f..22746462 100644 --- a/stack-clients/src/main/java/com/cmclinnovations/stack/clients/core/datasets/DCATUpdateQuery.java +++ b/stack-clients/src/main/java/com/cmclinnovations/stack/clients/core/datasets/DCATUpdateQuery.java @@ -22,7 +22,7 @@ import com.cmclinnovations.stack.clients.blazegraph.BlazegraphClient; import com.cmclinnovations.stack.clients.core.StackClient; import com.cmclinnovations.stack.clients.ontop.OntopClient; -import com.cmclinnovations.stack.clients.postgis.PostGISClient; +import com.cmclinnovations.stack.clients.postgis.Database; import com.cmclinnovations.stack.clients.rdf4j.Rdf4jClient; final class DCATUpdateQuery { @@ -213,10 +213,10 @@ private void addBlazegraphServer(Dataset dataset) { private void addPostGISServer(Dataset dataset) { boolean used = dataset.usesPostGIS(); - String database = dataset.getDatabase(); - String url = used ? PostGISClient.getInstance().readEndpointConfig().getJdbcURL(database) : null; + Database database = dataset.getDatabase(); + String url = used ? database.getEndpointConfig().getJdbcURL(database.getDatabaseName()) : null; - addService(postgisServiceVar, database, SparqlConstants.POSTGIS_SERVICE, url, null, null, used); + addService(postgisServiceVar, database.getDatabaseName(), SparqlConstants.POSTGIS_SERVICE, url, null, null, used); } private void addGeoServerServer(Dataset dataset) { diff --git a/stack-clients/src/main/java/com/cmclinnovations/stack/clients/core/datasets/Dataset.java b/stack-clients/src/main/java/com/cmclinnovations/stack/clients/core/datasets/Dataset.java index 1b3b4f2b..c53a3c82 100644 --- a/stack-clients/src/main/java/com/cmclinnovations/stack/clients/core/datasets/Dataset.java +++ b/stack-clients/src/main/java/com/cmclinnovations/stack/clients/core/datasets/Dataset.java @@ -19,6 +19,7 @@ import com.cmclinnovations.stack.clients.core.EndpointNames; import com.cmclinnovations.stack.clients.geoserver.GeoServerStyle; import com.cmclinnovations.stack.clients.geoserver.StaticGeoServerData; +import com.cmclinnovations.stack.clients.postgis.Database; import com.fasterxml.jackson.annotation.JacksonInject; import com.fasterxml.jackson.annotation.JsonCreator; import com.fasterxml.jackson.annotation.JsonIgnore; @@ -40,7 +41,7 @@ public class Dataset extends AbstractDataObject { private final Optional datasetDirectory; @JsonProperty - private final Optional database; + private final Optional database; @JsonProperty private final Optional namespace; @JsonProperty("workspace") @@ -99,7 +100,7 @@ public class Dataset extends AbstractDataObject { Dataset(String name, Optional description, Optional datasetDirectory, - Optional database, + Optional database, Optional namespace, Optional workspaceName, Optional> externalDatasetNames, @@ -140,12 +141,12 @@ public Path getDirectory() { return Path.of("/inputs", "data").resolve(datasetDirectory.orElse(Path.of(name))); } - public String getDatabase() { + public Database getDatabase() { if (database.isPresent()) { LOGGER.warn(NAME_DEPRECATION_NOTICE, "database", getName(), database.get()); return database.get(); } - return getName(); + return new Database(getName()); } public String getNamespace() { @@ -195,7 +196,7 @@ public List getOntopMappings() { public List getRules() { return rules.orElse(Collections.emptyList()); } - + public List getOntopLenses() { return ontopLenses.orElse(Collections.emptyList()); } diff --git a/stack-clients/src/main/java/com/cmclinnovations/stack/clients/core/datasets/DatasetLoader.java b/stack-clients/src/main/java/com/cmclinnovations/stack/clients/core/datasets/DatasetLoader.java index 1a38c57c..455d86d5 100644 --- a/stack-clients/src/main/java/com/cmclinnovations/stack/clients/core/datasets/DatasetLoader.java +++ b/stack-clients/src/main/java/com/cmclinnovations/stack/clients/core/datasets/DatasetLoader.java @@ -23,6 +23,7 @@ import com.cmclinnovations.stack.clients.geoserver.GeoServerClient; import com.cmclinnovations.stack.clients.geoserver.StaticGeoServerData; import com.cmclinnovations.stack.clients.ontop.OntopClient; +import com.cmclinnovations.stack.clients.postgis.Database; import com.cmclinnovations.stack.clients.postgis.PostGISClient; import com.cmclinnovations.stack.clients.rdf4j.Rdf4jClient; import com.cmclinnovations.stack.clients.utils.JsonHelper; @@ -207,11 +208,13 @@ private List getServiceDescriptions(String datasetName) { private void configurePostgres(Dataset dataset, List dataSubsets) { if (dataset.usesPostGIS()) { + Database database = dataset.getDatabase(); + String databaseName = database.getDatabaseName(); PostGISClient postGISClient = PostGISClient.getInstance(); - postGISClient.createDatabase(dataset.getDatabase()); + postGISClient.createDatabase(databaseName); dataSubsets.stream().filter(DataSubset::usesPostGIS) .filter(PostgresDataSubset.class::isInstance) - .forEach(subset -> postGISClient.createSchema(dataset.getDatabase(), + .forEach(subset -> postGISClient.createSchema(databaseName, ((PostgresDataSubset) subset).getSchema())); } } @@ -263,7 +266,10 @@ private void configureOntop(Dataset dataset, Path directory, List ontolo ServiceConfig newOntopServiceConfig = serviceManager.duplicateServiceConfig(EndpointNames.ONTOP, newOntopServiceName); - newOntopServiceConfig.setEnvironmentVariable(OntopService.ONTOP_DB_NAME, dataset.getDatabase()); + Database database = dataset.getDatabase(); + newOntopServiceConfig.setEnvironmentVariable(OntopService.ONTOP_DB_NAME, database.getDatabaseName()); + newOntopServiceConfig.getContainerSpec().getConfigs().stream().findFirst() + .ifPresent(config -> config.withConfigName(database.getEndpointName())); newOntopServiceConfig.getEndpoints() .replaceAll((endpointName, connection) -> new Connection( connection.getUrl(), @@ -278,7 +284,7 @@ private void configureOntop(Dataset dataset, Path directory, List ontolo OntopClient ontopClient = OntopClient.getInstance(newOntopServiceName); ontopMappings.forEach(mapping -> ontopClient.updateOBDA(directory.resolve(mapping))); - if (PostGISClient.DEFAULT_DATABASE_NAME.equals(dataset.getDatabase())) { + if (PostGISClient.DEFAULT_DATABASE_NAME.equals(database.getDatabaseName())) { OntopClient defaultOntopClient = OntopClient.getInstance(EndpointNames.ONTOP); ontopMappings.forEach(mapping -> defaultOntopClient.updateOBDA(directory.resolve(mapping))); } @@ -286,8 +292,9 @@ private void configureOntop(Dataset dataset, Path directory, List ontolo ontopClient.uploadOntology(catalogNamespace, ontologyDatasetNames); ontopClient.uploadRules(dataset.getRules().stream().map(directory::resolve).collect(Collectors.toList())); - - ontopClient.uploadLenses(dataset.getOntopLenses().stream().map(directory::resolve).collect(Collectors.toList())); + + ontopClient.uploadLenses( + dataset.getOntopLenses().stream().map(directory::resolve).collect(Collectors.toList())); } } } diff --git a/stack-clients/src/main/java/com/cmclinnovations/stack/clients/core/datasets/DatasetRemover.java b/stack-clients/src/main/java/com/cmclinnovations/stack/clients/core/datasets/DatasetRemover.java index ccc4adb0..628257e2 100644 --- a/stack-clients/src/main/java/com/cmclinnovations/stack/clients/core/datasets/DatasetRemover.java +++ b/stack-clients/src/main/java/com/cmclinnovations/stack/clients/core/datasets/DatasetRemover.java @@ -6,6 +6,7 @@ import com.cmclinnovations.stack.clients.blazegraph.BlazegraphClient; import com.cmclinnovations.stack.clients.core.StackClient; import com.cmclinnovations.stack.clients.geoserver.GeoServerClient; +import com.cmclinnovations.stack.clients.postgis.Database; import com.cmclinnovations.stack.clients.postgis.PostGISClient; import com.cmclinnovations.stack.services.ServiceManager; @@ -39,6 +40,7 @@ public void removeDataset(Dataset dataset) { serviceManager.removeService(StackClient.getStackName(), ontopServiceName); + Database database = dataset.getDatabase(); GeoServerClient geoServerClient = GeoServerClient.getInstance(); String workspaceName = dataset.getWorkspaceName(); // Ensure GeoServer workspace is removed @@ -48,7 +50,7 @@ public void removeDataset(Dataset dataset) { BlazegraphClient.getInstance().removeNamespace(dataset.getNamespace()); // Ensure PostGIS database is removed, if specified - PostGISClient.getInstance().removeDatabase(dataset.getDatabase()); + PostGISClient.getInstance().removeDatabase(database.getDatabaseName()); // Upload styles to GeoServer // dataset.getGeoserverStyles().forEach(style -> diff --git a/stack-clients/src/main/java/com/cmclinnovations/stack/clients/core/datasets/GeoServerDataSubset.java b/stack-clients/src/main/java/com/cmclinnovations/stack/clients/core/datasets/GeoServerDataSubset.java index a75981e0..8e81eff3 100644 --- a/stack-clients/src/main/java/com/cmclinnovations/stack/clients/core/datasets/GeoServerDataSubset.java +++ b/stack-clients/src/main/java/com/cmclinnovations/stack/clients/core/datasets/GeoServerDataSubset.java @@ -1,5 +1,7 @@ package com.cmclinnovations.stack.clients.core.datasets; +import com.cmclinnovations.stack.clients.postgis.Database; + public abstract class GeoServerDataSubset extends PostgresDataSubset { @Override @@ -13,6 +15,6 @@ void loadInternal(Dataset parent) { createLayers(parent.getWorkspaceName(), parent.getDatabase()); } - public abstract void createLayers(String workspaceName, String database); + public abstract void createLayers(String workspaceName, Database database); } diff --git a/stack-clients/src/main/java/com/cmclinnovations/stack/clients/core/datasets/OSMRouting.java b/stack-clients/src/main/java/com/cmclinnovations/stack/clients/core/datasets/OSMRouting.java index fcb1cc76..2c43d6c9 100644 --- a/stack-clients/src/main/java/com/cmclinnovations/stack/clients/core/datasets/OSMRouting.java +++ b/stack-clients/src/main/java/com/cmclinnovations/stack/clients/core/datasets/OSMRouting.java @@ -5,6 +5,7 @@ import com.cmclinnovations.stack.clients.core.Options; import com.cmclinnovations.stack.clients.geoserver.GeoServerClient; import com.cmclinnovations.stack.clients.geoserver.GeoServerVectorSettings; +import com.cmclinnovations.stack.clients.postgis.Database; import com.cmclinnovations.stack.clients.postgis.PGRoutingClient; import com.fasterxml.jackson.annotation.JsonProperty; @@ -26,13 +27,13 @@ public void loadData(Path dirPath, String database, String baseIRI) { } @Override - public void createLayers(String workspaceName, String database) { + public void createLayers(String workspaceName, Database database) { createLayer(workspaceName, database, prefixTableName("ways"), waysGeoServerSettings); createLayer(workspaceName, database, prefixTableName("ways_vertices_pgr"), verticesGeoServerSettings); createLayer(workspaceName, database, prefixTableName("pointsofinterest"), poiGeoServerSettings); } - private void createLayer(String workspaceName, String database, String layerName, + private void createLayer(String workspaceName, Database database, String layerName, GeoServerVectorSettings geoServerVectorSettings) { GeoServerClient.getInstance() .createPostGISLayer(workspaceName, database, getSchema(), layerName, geoServerVectorSettings); diff --git a/stack-clients/src/main/java/com/cmclinnovations/stack/clients/core/datasets/PostgresDataSubset.java b/stack-clients/src/main/java/com/cmclinnovations/stack/clients/core/datasets/PostgresDataSubset.java index 53e76c07..143ff8eb 100644 --- a/stack-clients/src/main/java/com/cmclinnovations/stack/clients/core/datasets/PostgresDataSubset.java +++ b/stack-clients/src/main/java/com/cmclinnovations/stack/clients/core/datasets/PostgresDataSubset.java @@ -7,6 +7,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import com.cmclinnovations.stack.clients.postgis.Database; import com.cmclinnovations.stack.clients.postgis.PostGISClient; import com.cmclinnovations.stack.clients.utils.JsonHelper; import com.fasterxml.jackson.annotation.JsonProperty; @@ -49,17 +50,18 @@ public boolean usesPostGIS() { @Override void loadInternal(Dataset parent) { - String database = parent.getDatabase(); + Database database = parent.getDatabase(); + String databaseName = database.getDatabaseName(); Optional subdirectory = this.getSubdirectory(); if (subdirectory.isPresent()) { Path dataSubsetDirectory = parent.getDirectory().resolve(subdirectory.get()); - PostGISClient.getInstance().resetSchema(database); - loadData(dataSubsetDirectory, database, parent.baseIRI()); + PostGISClient.getInstance().resetSchema(databaseName); + loadData(dataSubsetDirectory, databaseName, parent.baseIRI()); } else { logger.warn("No Subdirectory specified, Continuing with SQL process and creation without data upload"); } - runSQLPostProcess(database); - PostGISClient.getInstance().resetSchema(database); + runSQLPostProcess(databaseName); + PostGISClient.getInstance().resetSchema(databaseName); } public abstract void loadData(Path dataSubsetDir, String database, String baseIRI); diff --git a/stack-clients/src/main/java/com/cmclinnovations/stack/clients/core/datasets/Raster.java b/stack-clients/src/main/java/com/cmclinnovations/stack/clients/core/datasets/Raster.java index 851ad51e..3533706b 100644 --- a/stack-clients/src/main/java/com/cmclinnovations/stack/clients/core/datasets/Raster.java +++ b/stack-clients/src/main/java/com/cmclinnovations/stack/clients/core/datasets/Raster.java @@ -9,6 +9,7 @@ import com.cmclinnovations.stack.clients.geoserver.GeoServerClient; import com.cmclinnovations.stack.clients.geoserver.GeoServerRasterSettings; import com.cmclinnovations.stack.clients.geoserver.MultidimSettings; +import com.cmclinnovations.stack.clients.postgis.Database; import com.fasterxml.jackson.annotation.JsonProperty; public class Raster extends GeoServerDataSubset { @@ -30,7 +31,7 @@ public void loadData(Path dirPath, String database, String baseIRI) { } @Override - public void createLayers(String workspaceName, String database) { + public void createLayers(String workspaceName, Database database) { GeoServerClient.getInstance() .createGeoTiffLayer(workspaceName, getTable(), database, getSchema(), geoServerSettings, mdimSettings); diff --git a/stack-clients/src/main/java/com/cmclinnovations/stack/clients/core/datasets/Vector.java b/stack-clients/src/main/java/com/cmclinnovations/stack/clients/core/datasets/Vector.java index b15ef558..9471c977 100644 --- a/stack-clients/src/main/java/com/cmclinnovations/stack/clients/core/datasets/Vector.java +++ b/stack-clients/src/main/java/com/cmclinnovations/stack/clients/core/datasets/Vector.java @@ -6,6 +6,7 @@ import com.cmclinnovations.stack.clients.gdal.Ogr2OgrOptions; import com.cmclinnovations.stack.clients.geoserver.GeoServerClient; import com.cmclinnovations.stack.clients.geoserver.GeoServerVectorSettings; +import com.cmclinnovations.stack.clients.postgis.Database; import com.fasterxml.jackson.annotation.JsonProperty; public class Vector extends GeoServerDataSubset { @@ -24,7 +25,7 @@ public void loadData(Path dirPath, String database, String baseIRI) { } @Override - public void createLayers(String workspaceName, String database) { + public void createLayers(String workspaceName, Database database) { GeoServerClient.getInstance() .createPostGISLayer(workspaceName, database, getSchema(), getTable(), geoServerSettings); } diff --git a/stack-clients/src/main/java/com/cmclinnovations/stack/clients/geoserver/GeoServerClient.java b/stack-clients/src/main/java/com/cmclinnovations/stack/clients/geoserver/GeoServerClient.java index 423b52f9..5a088fc2 100644 --- a/stack-clients/src/main/java/com/cmclinnovations/stack/clients/geoserver/GeoServerClient.java +++ b/stack-clients/src/main/java/com/cmclinnovations/stack/clients/geoserver/GeoServerClient.java @@ -19,6 +19,7 @@ import com.cmclinnovations.stack.clients.core.RESTEndpointConfig; import com.cmclinnovations.stack.clients.core.StackClient; import com.cmclinnovations.stack.clients.docker.DockerClient; +import com.cmclinnovations.stack.clients.postgis.Database; import com.cmclinnovations.stack.clients.postgis.PostGISClient; import com.cmclinnovations.stack.clients.postgis.PostGISEndpointConfig; import com.cmclinnovations.stack.clients.utils.JsonHelper; @@ -38,8 +39,6 @@ public class GeoServerClient extends ClientWithEndpoint { private static final Logger logger = LoggerFactory.getLogger(GeoServerClient.class); private final GeoServerRESTManager manager; - private final PostGISEndpointConfig postgreSQLEndpoint; - private static GeoServerClient instance = null; public static final Path SERVING_DIRECTORY = Path.of("/opt/geoserver_data/www"); @@ -76,8 +75,6 @@ public GeoServerClient(URL restURL, String username, String password) { } manager = new GeoServerRESTManager(restURL, username, password); - - postgreSQLEndpoint = readEndpointConfig(EndpointNames.POSTGIS, PostGISEndpointConfig.class); } public void createWorkspace(String workspaceName) { @@ -167,17 +164,17 @@ public void loadIcons(Path baseDirectory, String iconDir) { } } - public void createPostGISDataStore(String workspaceName, String name, String database, String schema) { + public void createPostGISDataStore(String workspaceName, String name, Database database, String schema) { if (manager.getReader().existsDatastore(workspaceName, name)) { logger.info("GeoServer datastore '{}' already exists.", name); } else { - + PostGISEndpointConfig postgreSQLEndpoint = database.getEndpointConfig(); GSPostGISDatastoreEncoder encoder = new GSPostGISDatastoreEncoder(name); encoder.setHost(postgreSQLEndpoint.getHostName()); encoder.setPort(Integer.parseInt(postgreSQLEndpoint.getPort())); encoder.setUser(postgreSQLEndpoint.getUsername()); encoder.setPassword(postgreSQLEndpoint.getPassword()); - encoder.setDatabase(database); + encoder.setDatabase(database.getDatabaseName()); encoder.setSchema(schema); encoder.setValidateConnections(true); @@ -190,9 +187,9 @@ public void createPostGISDataStore(String workspaceName, String name, String dat } } - public void createPostGISLayer(String workspaceName, String database, String schema, String layerName, + public void createPostGISLayer(String workspaceName, Database database, String schema, String layerName, GeoServerVectorSettings geoServerSettings) { - String storeName = database; + String storeName = database.getDatabaseName(); // Need to include the "Util.DEFAULT_QUIET_ON_NOT_FOUND" argument because the // 2-arg version of "existsLayer" incorrectly calls the 3-arg version of the @@ -239,14 +236,15 @@ private void configureVirtualTable(String layerName, GSFeatureTypeEncoder fte, G } } - public void createGeoTiffLayer(String workspaceName, String name, String database, String schema, + public void createGeoTiffLayer(String workspaceName, String name, Database database, String schema, GeoServerRasterSettings geoServerSettings, MultidimSettings mdimSettings) { if (manager.getReader().existsCoveragestore(workspaceName, name)) { logger.info("GeoServer coverage store '{}' already exists.", name); } else { + PostGISEndpointConfig postgreSQLEndpoint = database.getEndpointConfig(); String geoserverRasterIndexDatabaseName = database + GEOSERVER_RASTER_INDEX_DATABASE_SUFFIX; - PostGISClient postgisClient = PostGISClient.getInstance(); + PostGISClient postgisClient = PostGISClient.getInstance(postgreSQLEndpoint.getName()); postgisClient.createDatabase(geoserverRasterIndexDatabaseName); postgisClient.createSchema(geoserverRasterIndexDatabaseName, schema); @@ -267,7 +265,7 @@ public void createGeoTiffLayer(String workspaceName, String name, String databas datastoreProperties.putIfAbsent("preparedStatements", "true"); StringWriter stringWriter = new StringWriter(); - Path geotiffDir = Path.of(StackClient.GEOTIFFS_DIR, database, schema, name); + Path geotiffDir = Path.of(StackClient.GEOTIFFS_DIR, database.getDatabaseName(), schema, name); try { Map files = new HashMap<>(); @@ -350,14 +348,12 @@ private void processDimensions(GeoServerDimensionSettings dimensionSettings, GSR public void addProjectionsToGeoserver(String wktString, String srid) { String geoserverContainerId = getContainerId("geoserver"); - DockerClient dockerClient = DockerClient.getInstance(); - - dockerClient.makeDir(geoserverContainerId, USER_PROJECTIONS_DIR); + DockerClient.getInstance().makeDir(geoserverContainerId, USER_PROJECTIONS_DIR); sendFileContent(geoserverContainerId, Path.of(USER_PROJECTIONS_DIR, "epsg.properties"), (srid + "=" + wktString + "\n").getBytes()); - GeoServerClient.getInstance().reload(); + reload(); } } diff --git a/stack-clients/src/main/java/com/cmclinnovations/stack/clients/postgis/Database.java b/stack-clients/src/main/java/com/cmclinnovations/stack/clients/postgis/Database.java new file mode 100644 index 00000000..d7cfd518 --- /dev/null +++ b/stack-clients/src/main/java/com/cmclinnovations/stack/clients/postgis/Database.java @@ -0,0 +1,54 @@ +package com.cmclinnovations.stack.clients.postgis; + +import com.cmclinnovations.stack.clients.core.EndpointNames; +import com.cmclinnovations.stack.clients.docker.DockerConfigHandler; +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; + +public class Database { + + private final String databaseName; + + private PostGISEndpointConfig endpointConfig; + + /** + * Constructor for the short form (just the name as a string) + */ + @JsonCreator + public Database(String databaseName) { + this.databaseName = databaseName; + } + + /** + * Constructor for the long form (full JSON object) + */ + @JsonCreator + public Database(@JsonProperty(value = "name") String name, + @JsonProperty(value = "endpoint") PostGISEndpointConfig endpointConfig) { + this.databaseName = name; + this.endpointConfig = endpointConfig; + DockerConfigHandler.writeEndpointConfig(endpointConfig); + } + + public String getEndpointName() { + return getEndpointConfig().getName(); + } + + public String getDatabaseName() { + return databaseName; + } + + public PostGISEndpointConfig getEndpointConfig() { + if (null == endpointConfig) { + endpointConfig = DockerConfigHandler.readEndpointConfig(EndpointNames.POSTGIS, + PostGISEndpointConfig.class); + } + return endpointConfig; + } + + @Override + public String toString() { + return databaseName; + } + +} diff --git a/stack-clients/src/main/java/com/cmclinnovations/stack/clients/postgis/PostGISClient.java b/stack-clients/src/main/java/com/cmclinnovations/stack/clients/postgis/PostGISClient.java index 12e7219a..a51c9dee 100644 --- a/stack-clients/src/main/java/com/cmclinnovations/stack/clients/postgis/PostGISClient.java +++ b/stack-clients/src/main/java/com/cmclinnovations/stack/clients/postgis/PostGISClient.java @@ -6,6 +6,8 @@ import java.sql.Connection; import java.sql.SQLException; import java.sql.Statement; +import java.util.HashMap; +import java.util.Map; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -23,17 +25,22 @@ public class PostGISClient extends ClientWithEndpoint { private static final Logger logger = LoggerFactory.getLogger(PostGISClient.class); - private static PostGISClient instance = null; + private static Map instances = new HashMap<>(); public static PostGISClient getInstance() { - if (null == instance) { - instance = new PostGISClient(); - } - return instance; + return getInstance(EndpointNames.POSTGIS); + } + + public static PostGISClient getInstance(String name) { + return instances.computeIfAbsent(name, PostGISClient::new); } protected PostGISClient() { - super(EndpointNames.POSTGIS, PostGISEndpointConfig.class); + this(EndpointNames.POSTGIS); + } + + protected PostGISClient(String name) { + super(name, PostGISEndpointConfig.class); } private Connection getDefaultConnection() throws SQLException { @@ -169,7 +176,7 @@ public RemoteRDBStoreClient getRemoteStoreClient(String database) { public void resetSchema(String database) { try (InputStream is = PostGISClient.class.getResourceAsStream("postgis_reset_schema.sql")) { String sqlQuery = new String(is.readAllBytes()).replace("{database}", database); - PostGISClient.getInstance().getRemoteStoreClient(database).executeUpdate(sqlQuery); + getRemoteStoreClient(database).executeUpdate(sqlQuery); } catch (IOException ex) { throw new RuntimeException("Failed to read resource file 'postgis_reset_schema.sql'.", ex); } diff --git a/stack-clients/src/main/java/com/cmclinnovations/stack/clients/rdf4j/Rdf4jClient.java b/stack-clients/src/main/java/com/cmclinnovations/stack/clients/rdf4j/Rdf4jClient.java index d75c0528..6dd94585 100644 --- a/stack-clients/src/main/java/com/cmclinnovations/stack/clients/rdf4j/Rdf4jClient.java +++ b/stack-clients/src/main/java/com/cmclinnovations/stack/clients/rdf4j/Rdf4jClient.java @@ -4,7 +4,6 @@ import org.eclipse.rdf4j.federated.repository.FedXRepositoryConfigBuilder; import org.eclipse.rdf4j.repository.config.RepositoryConfig; -import org.eclipse.rdf4j.repository.config.RepositoryImplConfig; import org.eclipse.rdf4j.repository.manager.RemoteRepositoryManager; import org.eclipse.rdf4j.repository.sail.config.SailRepositoryConfig; import org.eclipse.rdf4j.repository.sparql.config.SPARQLRepositoryConfig; diff --git a/stack-clients/src/test/java/com/cmclinnovations/stack/clients/core/datasets/DCATUpdateQueryTest.java b/stack-clients/src/test/java/com/cmclinnovations/stack/clients/core/datasets/DCATUpdateQueryTest.java index 82bcca6b..b7a8aec0 100644 --- a/stack-clients/src/test/java/com/cmclinnovations/stack/clients/core/datasets/DCATUpdateQueryTest.java +++ b/stack-clients/src/test/java/com/cmclinnovations/stack/clients/core/datasets/DCATUpdateQueryTest.java @@ -36,6 +36,7 @@ import com.cmclinnovations.stack.clients.core.datasets.DatasetBuilder.Service; import com.cmclinnovations.stack.clients.ontop.OntopClient; import com.cmclinnovations.stack.clients.ontop.OntopEndpointConfig; +import com.cmclinnovations.stack.clients.postgis.Database; import com.cmclinnovations.stack.clients.postgis.PostGISClient; import com.cmclinnovations.stack.clients.postgis.PostGISEndpointConfig; import com.cmclinnovations.stack.clients.rdf4j.Rdf4jClient; @@ -163,7 +164,8 @@ void testAddPostGIS() { buildAndRunQuery(dataset); }, () -> { Dataset dataset = new DatasetBuilder("testDataset").withDescription("Dataset for testing2") - .withDatasetDirectory("test2").withServices(Service.POSTGIS).withDatabase("database1").build(); + .withDatasetDirectory("test2").withServices(Service.POSTGIS).withDatabase(new Database("database1")) + .build(); buildAndRunQuery(dataset); }, () -> { Dataset dataset = new DatasetBuilder("testDataset3").withDescription("Dataset for testing3") diff --git a/stack-clients/src/test/java/com/cmclinnovations/stack/clients/core/datasets/DatasetBuilder.java b/stack-clients/src/test/java/com/cmclinnovations/stack/clients/core/datasets/DatasetBuilder.java index c7af436d..18d3b101 100644 --- a/stack-clients/src/test/java/com/cmclinnovations/stack/clients/core/datasets/DatasetBuilder.java +++ b/stack-clients/src/test/java/com/cmclinnovations/stack/clients/core/datasets/DatasetBuilder.java @@ -7,6 +7,7 @@ import com.cmclinnovations.stack.clients.blazegraph.Namespace; import com.cmclinnovations.stack.clients.geoserver.GeoServerStyle; import com.cmclinnovations.stack.clients.geoserver.StaticGeoServerData; +import com.cmclinnovations.stack.clients.postgis.Database; class DatasetBuilder { @@ -16,7 +17,7 @@ class DatasetBuilder { private Path datasetDirectory; - private String database; + private Database database; private Namespace namespace; @@ -65,7 +66,7 @@ public DatasetBuilder withDatasetDirectory(String datasetDirectory) { return this; } - public DatasetBuilder withDatabase(String database) { + public DatasetBuilder withDatabase(Database database) { this.database = database; return this; } @@ -160,7 +161,7 @@ static class TestDataset extends Dataset { private TestDataset(String name, Optional description, Optional datasetDirectory, - Optional database, + Optional database, Optional namespace, Optional workspaceName, Optional> externalDatasetNames, diff --git a/stack-clients/src/test/java/com/cmclinnovations/stack/clients/core/datasets/DatasetTest.java b/stack-clients/src/test/java/com/cmclinnovations/stack/clients/core/datasets/DatasetTest.java index e3bb0875..931d8348 100644 --- a/stack-clients/src/test/java/com/cmclinnovations/stack/clients/core/datasets/DatasetTest.java +++ b/stack-clients/src/test/java/com/cmclinnovations/stack/clients/core/datasets/DatasetTest.java @@ -40,7 +40,7 @@ void testDeserialisingTrivial() { Assertions.assertEquals(name, dataset.getDescription()); Assertions.assertEquals(Path.of("/inputs", "data", name), dataset.getDirectory()); Assertions.assertEquals(name, dataset.getNamespace()); - Assertions.assertEquals(name, dataset.getDatabase()); + Assertions.assertEquals(name, dataset.getDatabase().getDatabaseName()); Assertions.assertEquals(name, dataset.getWorkspaceName()); Assertions.assertFalse(dataset.isSkip()); Assertions.assertEquals(SparqlConstants.DEFAULT_BASE_IRI, dataset.baseIRI()); @@ -65,7 +65,7 @@ void testDeserialisingNames() { Assertions.assertEquals("Test description", dataset.getDescription()); Assertions.assertEquals(Path.of("/inputs", "data", "datasetDirectory"), dataset.getDirectory()); Assertions.assertEquals("namespace", dataset.getNamespace()); - Assertions.assertEquals("database", dataset.getDatabase()); + Assertions.assertEquals("database", dataset.getDatabase().getDatabaseName()); Assertions.assertEquals("workspace", dataset.getWorkspaceName()); Assertions.assertTrue(dataset.isSkip()); } diff --git a/stack-clients/src/test/java/com/cmclinnovations/stack/clients/geoserver/GeoServerClientTest.java b/stack-clients/src/test/java/com/cmclinnovations/stack/clients/geoserver/GeoServerClientTest.java index 4e22c52d..44e3e675 100644 --- a/stack-clients/src/test/java/com/cmclinnovations/stack/clients/geoserver/GeoServerClientTest.java +++ b/stack-clients/src/test/java/com/cmclinnovations/stack/clients/geoserver/GeoServerClientTest.java @@ -42,6 +42,7 @@ import com.cmclinnovations.stack.clients.mocks.MockGeoServer; import com.cmclinnovations.stack.clients.mocks.MockPostGIS; import com.cmclinnovations.stack.clients.mocks.MockServiceWithFileSystem; +import com.cmclinnovations.stack.clients.postgis.Database; import com.cmclinnovations.stack.clients.utils.JsonHelper; import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.ObjectMapper; @@ -51,7 +52,7 @@ public class GeoServerClientTest { private static final String RASTER_SCHEMA_NAME = "existing_raster_schema"; private static final String VECTOR_SCHEMA_NAME = "existing_vector_schema"; - private static final String DATABASE_NAME = "existing_database"; + private static final Database DATABASE = new Database("existing_database"); private static final String EXISTING_WORKSPACE = "existingWorkspace"; private static final String NEW_WORKSPACE = "newWorkspace"; private static final String EXISTING_COVERAGE_STORE = "existingCoverageStore"; @@ -111,8 +112,8 @@ void testCreateGeoTiffLayerExisting() { "/rest/workspaces/" + EXISTING_WORKSPACE + "/coveragestores/" + EXISTING_COVERAGE_STORE + ".xml", 200); - geoServerClient.createGeoTiffLayer(EXISTING_WORKSPACE, EXISTING_COVERAGE_STORE, DATABASE_NAME, - RASTER_SCHEMA_NAME, new GeoServerRasterSettings(), new MultidimSettings()); + geoServerClient.createGeoTiffLayer(EXISTING_WORKSPACE, EXISTING_COVERAGE_STORE, DATABASE, RASTER_SCHEMA_NAME, + new GeoServerRasterSettings(), new MultidimSettings()); } @Test @@ -125,8 +126,8 @@ void testCreateGeoTiffLayerNew() { "/rest/workspaces/" + EXISTING_WORKSPACE + "/coveragestores/" + NEW_COVERAGE_STORE + "/external.imagemosaic", 200, - request().withBody(Path.of("/geotiffs/existing_database/existing_raster_schema/newCoverageStore").toFile() - .toURI().toString()), + request().withBody(Path.of("/geotiffs/existing_database/existing_raster_schema/newCoverageStore") + .toFile().toURI().toString()), response().withBody("")); mockGeoServer.addExpectation(POST, @@ -138,7 +139,7 @@ void testCreateGeoTiffLayerNew() { request().withBody( "truetrue")); - geoServerClient.createGeoTiffLayer(EXISTING_WORKSPACE, NEW_COVERAGE_STORE, DATABASE_NAME, RASTER_SCHEMA_NAME, + geoServerClient.createGeoTiffLayer(EXISTING_WORKSPACE, NEW_COVERAGE_STORE, DATABASE, RASTER_SCHEMA_NAME, new GeoServerRasterSettings(), new MultidimSettings()); } @@ -147,8 +148,7 @@ void testCreatePostGISDataStoreExisting() { mockGeoServer.addExpectation(GET, "/rest/workspaces/" + EXISTING_WORKSPACE + "/datastores/" + NEW_POSTGIS_STORE + ".xml", 200); - geoServerClient.createPostGISDataStore(EXISTING_WORKSPACE, NEW_POSTGIS_STORE, DATABASE_NAME, - VECTOR_SCHEMA_NAME); + geoServerClient.createPostGISDataStore(EXISTING_WORKSPACE, NEW_POSTGIS_STORE, DATABASE, VECTOR_SCHEMA_NAME); } @Test @@ -161,8 +161,7 @@ void testCreatePostGISDataStoreNew() { request().withBody( "newPostgresStorepostgis110100020truefalse50falsetest-postgis1234userexisting_databaseexisting_vector_schematruePostGIS")); - geoServerClient.createPostGISDataStore(EXISTING_WORKSPACE, NEW_POSTGIS_STORE, DATABASE_NAME, - VECTOR_SCHEMA_NAME); + geoServerClient.createPostGISDataStore(EXISTING_WORKSPACE, NEW_POSTGIS_STORE, DATABASE, VECTOR_SCHEMA_NAME); } @Test @@ -171,7 +170,7 @@ void testCreatePostGISLayerExisting() { String layerName = "layerName"; mockGeoServer.addExpectation(GET, "/rest/layers/" + EXISTING_WORKSPACE + ":" + layerName + ".xml", 200); - geoServerClient.createPostGISLayer(EXISTING_WORKSPACE, DATABASE_NAME, VECTOR_SCHEMA_NAME, layerName, + geoServerClient.createPostGISLayer(EXISTING_WORKSPACE, DATABASE, VECTOR_SCHEMA_NAME, layerName, new GeoServerVectorSettings()); } @@ -180,11 +179,11 @@ void testCreatePostGISLayerExistingStore() { String layerName = "layerName"; mockGeoServer.addExpectation(GET, "/rest/layers/" + EXISTING_WORKSPACE + ":" + layerName + ".xml", 404); - mockGeoServer.addExpectation(GET, - "/rest/workspaces/" + EXISTING_WORKSPACE + "/datastores/" + DATABASE_NAME + ".xml", 200); + mockGeoServer.addExpectation(GET, "/rest/workspaces/" + EXISTING_WORKSPACE + "/datastores/" + DATABASE + ".xml", + 200); mockGeoServer.addExpectation(POST, - "/rest/workspaces/" + EXISTING_WORKSPACE + "/datastores/" + DATABASE_NAME + "/featuretypes", 200, + "/rest/workspaces/" + EXISTING_WORKSPACE + "/datastores/" + DATABASE + "/featuretypes", 200, request().withBody(XmlBody.xml( "trueNONElayerNamelayerName", MediaType.TEXT_XML))); @@ -193,7 +192,7 @@ void testCreatePostGISLayerExistingStore() { request().withBody( "truetrue")); - geoServerClient.createPostGISLayer(EXISTING_WORKSPACE, DATABASE_NAME, VECTOR_SCHEMA_NAME, layerName, + geoServerClient.createPostGISLayer(EXISTING_WORKSPACE, DATABASE, VECTOR_SCHEMA_NAME, layerName, new GeoServerVectorSettings()); } @@ -238,13 +237,13 @@ void testCreatePostGISLayerNew(String testName, GeoServerVectorSettings geoServe "existing_databasepostgis110100020truefalse50falsetest-postgis1234userexisting_databaseexisting_vector_schematruePostGIS")); mockGeoServer.addExpectation(GET, - "/rest/workspaces/" + EXISTING_WORKSPACE + "/datastores/" + DATABASE_NAME + ".xml", 404); + "/rest/workspaces/" + EXISTING_WORKSPACE + "/datastores/" + DATABASE + ".xml", 404); String layerName = "layerName"; mockGeoServer.addExpectation(GET, "/rest/layers/" + EXISTING_WORKSPACE + ":" + layerName + ".xml", 404); mockGeoServer.addExpectation(POST, - "/rest/workspaces/" + EXISTING_WORKSPACE + "/datastores/" + DATABASE_NAME + "/featuretypes", + "/rest/workspaces/" + EXISTING_WORKSPACE + "/datastores/" + DATABASE + "/featuretypes", 200, request().withBody(featureTypesBody)); mockGeoServer.addExpectation(PUT, "/rest/layers/" + EXISTING_WORKSPACE + ":" + layerName, 200, @@ -256,10 +255,10 @@ void testCreatePostGISLayerNew(String testName, GeoServerVectorSettings geoServe && null != (sql = virtualTable.getSql()) && sql.startsWith("@")) { moveConfigFileAndRun(sql.replaceAll(".*/", ""), filePath -> geoServerClient - .createPostGISLayer(EXISTING_WORKSPACE, DATABASE_NAME, VECTOR_SCHEMA_NAME, layerName, + .createPostGISLayer(EXISTING_WORKSPACE, DATABASE, VECTOR_SCHEMA_NAME, layerName, geoServerVectorSettings)); } else { - geoServerClient.createPostGISLayer(EXISTING_WORKSPACE, DATABASE_NAME, VECTOR_SCHEMA_NAME, layerName, + geoServerClient.createPostGISLayer(EXISTING_WORKSPACE, DATABASE, VECTOR_SCHEMA_NAME, layerName, geoServerVectorSettings); } } diff --git a/stack-clients/src/test/java/com/cmclinnovations/stack/clients/mocks/MockPostGIS.java b/stack-clients/src/test/java/com/cmclinnovations/stack/clients/mocks/MockPostGIS.java index c957c3a3..990de5fb 100644 --- a/stack-clients/src/test/java/com/cmclinnovations/stack/clients/mocks/MockPostGIS.java +++ b/stack-clients/src/test/java/com/cmclinnovations/stack/clients/mocks/MockPostGIS.java @@ -30,6 +30,7 @@ public MockPostGIS() { postGISClientFactoryMock = mockStatic(PostGISClient.class); postGISClientFactoryMock.when(PostGISClient::getInstance).thenReturn(postGISClientMock); + postGISClientFactoryMock.when(()->PostGISClient.getInstance("postgis")).thenReturn(postGISClientMock); } public void addOverride(Consumer rule) { From 45bec6b7a1d70787c596587ae9788437d1d83b72 Mon Sep 17 00:00:00 2001 From: George Brownbridge Date: Mon, 10 Nov 2025 17:29:14 +0000 Subject: [PATCH 4/4] external-postgres-endpoints: Added a `Database::ensureDefault` method to prevent certain operations on external databases. --- .../cmclinnovations/stack/clients/core/datasets/CityDB.java | 1 + .../stack/clients/core/datasets/DatasetLoader.java | 1 + .../stack/clients/core/datasets/DatasetRemover.java | 1 + .../stack/clients/core/datasets/PostgresDataSubset.java | 1 + .../com/cmclinnovations/stack/clients/postgis/Database.java | 6 ++++++ 5 files changed, 10 insertions(+) diff --git a/stack-clients/src/main/java/com/cmclinnovations/stack/clients/core/datasets/CityDB.java b/stack-clients/src/main/java/com/cmclinnovations/stack/clients/core/datasets/CityDB.java index efd1d5a6..70550c89 100644 --- a/stack-clients/src/main/java/com/cmclinnovations/stack/clients/core/datasets/CityDB.java +++ b/stack-clients/src/main/java/com/cmclinnovations/stack/clients/core/datasets/CityDB.java @@ -64,6 +64,7 @@ protected void setPreviousFile(Path previousFilePath) { @Override void loadInternal(Dataset parent) { Database database = parent.getDatabase(); + database.ensureDefault(); String databaseName = database.getDatabaseName(); super.loadInternal(parent); diff --git a/stack-clients/src/main/java/com/cmclinnovations/stack/clients/core/datasets/DatasetLoader.java b/stack-clients/src/main/java/com/cmclinnovations/stack/clients/core/datasets/DatasetLoader.java index 455d86d5..ceb022e7 100644 --- a/stack-clients/src/main/java/com/cmclinnovations/stack/clients/core/datasets/DatasetLoader.java +++ b/stack-clients/src/main/java/com/cmclinnovations/stack/clients/core/datasets/DatasetLoader.java @@ -209,6 +209,7 @@ private List getServiceDescriptions(String datasetName) { private void configurePostgres(Dataset dataset, List dataSubsets) { if (dataset.usesPostGIS()) { Database database = dataset.getDatabase(); + database.ensureDefault(); String databaseName = database.getDatabaseName(); PostGISClient postGISClient = PostGISClient.getInstance(); postGISClient.createDatabase(databaseName); diff --git a/stack-clients/src/main/java/com/cmclinnovations/stack/clients/core/datasets/DatasetRemover.java b/stack-clients/src/main/java/com/cmclinnovations/stack/clients/core/datasets/DatasetRemover.java index 628257e2..56f44f6c 100644 --- a/stack-clients/src/main/java/com/cmclinnovations/stack/clients/core/datasets/DatasetRemover.java +++ b/stack-clients/src/main/java/com/cmclinnovations/stack/clients/core/datasets/DatasetRemover.java @@ -41,6 +41,7 @@ public void removeDataset(Dataset dataset) { serviceManager.removeService(StackClient.getStackName(), ontopServiceName); Database database = dataset.getDatabase(); + database.ensureDefault(); GeoServerClient geoServerClient = GeoServerClient.getInstance(); String workspaceName = dataset.getWorkspaceName(); // Ensure GeoServer workspace is removed diff --git a/stack-clients/src/main/java/com/cmclinnovations/stack/clients/core/datasets/PostgresDataSubset.java b/stack-clients/src/main/java/com/cmclinnovations/stack/clients/core/datasets/PostgresDataSubset.java index 143ff8eb..883e5cfe 100644 --- a/stack-clients/src/main/java/com/cmclinnovations/stack/clients/core/datasets/PostgresDataSubset.java +++ b/stack-clients/src/main/java/com/cmclinnovations/stack/clients/core/datasets/PostgresDataSubset.java @@ -51,6 +51,7 @@ public boolean usesPostGIS() { @Override void loadInternal(Dataset parent) { Database database = parent.getDatabase(); + database.ensureDefault(); String databaseName = database.getDatabaseName(); Optional subdirectory = this.getSubdirectory(); if (subdirectory.isPresent()) { diff --git a/stack-clients/src/main/java/com/cmclinnovations/stack/clients/postgis/Database.java b/stack-clients/src/main/java/com/cmclinnovations/stack/clients/postgis/Database.java index d7cfd518..0ea8c376 100644 --- a/stack-clients/src/main/java/com/cmclinnovations/stack/clients/postgis/Database.java +++ b/stack-clients/src/main/java/com/cmclinnovations/stack/clients/postgis/Database.java @@ -51,4 +51,10 @@ public String toString() { return databaseName; } + public void ensureDefault() { + if (EndpointNames.POSTGIS != getEndpointName()) { + throw new IllegalStateException("This class/method does not support non-default Postgres databases."); + } + } + }