diff --git a/pom.xml b/pom.xml index 6a09f57cc7fd91e3d0a2a930c5c4e435cb6bca4d..63a1dc1961da0f1873ba5a7017dcc4cd0136d24a 100644 --- a/pom.xml +++ b/pom.xml @@ -620,7 +620,7 @@ <artifactId>maven-surefire-plugin</artifactId> <version>3.5.2</version> <configuration> - <argLine>-Xmx${tests.jvm.xmx} @{jacoco.argLine} -Daws.java.v1.disableDeprecationAnnouncement=true</argLine> + <argLine>-Xmx${tests.jvm.xmx} @{jacoco.argLine}</argLine> </configuration> </plugin> <plugin> @@ -716,7 +716,7 @@ <plugin> <groupId>com.smartbear.soapui</groupId> <artifactId>soapui-maven-plugin</artifactId> - <version>5.7.2</version> + <version>5.8.0</version> </plugin> <!-- asciidoc --> <plugin> @@ -1192,9 +1192,9 @@ <scope>provided</scope> </dependency> <dependency> - <groupId>com.amazonaws</groupId> - <artifactId>aws-java-sdk-bom</artifactId> - <version>1.12.780</version> + <groupId>software.amazon.awssdk</groupId> + <artifactId>bom</artifactId> + <version>2.30.10</version> <type>pom</type> <scope>import</scope> </dependency> diff --git a/xplan-cli/pom.xml b/xplan-cli/pom.xml index eed11ac0173d69806673f7d6f24a01c1cb0662a4..165cf0c66150be001dea70591e1ddc517f7e5f7e 100644 --- a/xplan-cli/pom.xml +++ b/xplan-cli/pom.xml @@ -12,7 +12,7 @@ </parent> <properties> - <docker-contextTarFile.expectedSizeInMat10pct>102</docker-contextTarFile.expectedSizeInMat10pct> + <docker-contextTarFile.expectedSizeInMat10pct>115</docker-contextTarFile.expectedSizeInMat10pct> </properties> <profiles> @@ -35,6 +35,17 @@ <build> <plugins> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-jar-plugin</artifactId> + <configuration> + <archive> + <manifest> + <addDefaultImplementationEntries>true</addDefaultImplementationEntries> + </manifest> + </archive> + </configuration> + </plugin> <plugin> <groupId>org.codehaus.mojo</groupId> <artifactId>appassembler-maven-plugin</artifactId> diff --git a/xplan-cli/src/main/java/de/latlon/xplanbox/cli/main/MainCommand.java b/xplan-cli/src/main/java/de/latlon/xplanbox/cli/main/MainCommand.java index df61fbdc240f9960edde62969944274b96008b6c..64ed8cd83e0c79d61bad9e0dda42704c94b84b8b 100644 --- a/xplan-cli/src/main/java/de/latlon/xplanbox/cli/main/MainCommand.java +++ b/xplan-cli/src/main/java/de/latlon/xplanbox/cli/main/MainCommand.java @@ -23,6 +23,7 @@ package de.latlon.xplanbox.cli.main; import de.latlon.xplanbox.cli.admin.AdminCommand; import de.latlon.xplanbox.cli.manage.ManageCommand; import de.latlon.xplanbox.cli.validate.ValidateCommand; +import de.latlon.xplanbox.cli.version.VersionCommand; import org.springframework.stereotype.Component; import picocli.CommandLine; @@ -30,8 +31,8 @@ import picocli.CommandLine; * @author <a href="mailto:goltz@lat-lon.de">Lyn Goltz </a> */ @Component -@CommandLine.Command(name = "xpb", description = "XPlanCLI", - subcommands = { CommandLine.HelpCommand.class, ValidateCommand.class, ManageCommand.class, AdminCommand.class }) +@CommandLine.Command(name = "xpb", description = "XPlanCLI", subcommands = { CommandLine.HelpCommand.class, + VersionCommand.class, ValidateCommand.class, ManageCommand.class, AdminCommand.class }) public class MainCommand implements Runnable { @Override diff --git a/xplan-cli/src/main/java/de/latlon/xplanbox/cli/version/VersionCommand.java b/xplan-cli/src/main/java/de/latlon/xplanbox/cli/version/VersionCommand.java new file mode 100644 index 0000000000000000000000000000000000000000..a49339df501043479b18acf833072cd71de4d0eb --- /dev/null +++ b/xplan-cli/src/main/java/de/latlon/xplanbox/cli/version/VersionCommand.java @@ -0,0 +1,45 @@ +/*- + * #%L + * xplan-cli - Kommandozeilenwerkzeuge fuer die xPlanBox + * %% + * Copyright (C) 2008 - 2025 Freie und Hansestadt Hamburg, developed by lat/lon gesellschaft für raumbezogene Informationssysteme mbH + * %% + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * #L% + */ +package de.latlon.xplanbox.cli.version; + +import picocli.CommandLine; + +/** + * @author <a href="mailto:goltz@lat-lon.de">Lyn Goltz </a> + * @since 8.1 + */ +@CommandLine.Command(name = "version", aliases = { "-v", "-V", "v" }, + version = { "xPlanBox %s", "JVM: ${java.version} (${java.vendor} ${java.vm.name} ${java.vm.version})", + "OS: ${os.name} ${os.version} ${os.arch}" }) +public class VersionCommand implements Runnable { + + @Override + public void run() { + CommandLine commandLine = new CommandLine(new VersionCommand()); + commandLine.printVersionHelp(System.out, commandLine.getColorScheme().ansi(), parseVersion()); + } + + public String parseVersion() { + Package thisPackage = getClass().getPackage(); + return thisPackage.getImplementationVersion(); + } + +} diff --git a/xplan-core/xplan-core-api/src/main/java/de/latlon/xplanbox/api/commons/handler/AbstractAsyncWrapper.java b/xplan-core/xplan-core-api/src/main/java/de/latlon/xplanbox/api/commons/handler/AbstractAsyncWrapper.java index bc2268c7c2d2d9984996dc8f64b2f5fa1e3dbbaa..69f5fd32eea59ad20f6f4f0231e254a2f5a75a68 100644 --- a/xplan-core/xplan-core-api/src/main/java/de/latlon/xplanbox/api/commons/handler/AbstractAsyncWrapper.java +++ b/xplan-core/xplan-core-api/src/main/java/de/latlon/xplanbox/api/commons/handler/AbstractAsyncWrapper.java @@ -22,14 +22,16 @@ package de.latlon.xplanbox.api.commons.handler; import static org.slf4j.LoggerFactory.getLogger; +import java.time.Instant; +import java.time.LocalDateTime; +import java.time.ZoneId; import java.util.Collections; import java.util.HashMap; import java.util.Map; -import de.latlon.core.validator.events.ValidationRequestedEvent; import de.latlon.core.validator.events.EventSender; +import de.latlon.core.validator.events.ValidationRequestedEvent; import de.latlon.xplanbox.api.commons.exception.AsyncTimeout; -import org.joda.time.Instant; import org.slf4j.Logger; /** @@ -54,7 +56,10 @@ public abstract class AbstractAsyncWrapper { LOG.info("Event sent. Waiting for processing of {}", uuid); waitingUuids.put(uuid, null); - long maxWaitDate = Long.MAX_VALUE; // TODO: which value would be correct? + // TODO: which value would be correct? + LocalDateTime maxWaitDateTime = Instant.ofEpochMilli(Long.MAX_VALUE) + .atZone(ZoneId.systemDefault()) + .toLocalDateTime(); boolean waitFinished = false; while (!waitFinished) { synchronized (waitingUuids) { @@ -70,7 +75,7 @@ public abstract class AbstractAsyncWrapper { LOG.info("Finished waiting for processing of {}", uuid); waitFinished = true; } - else if (Instant.now().isAfter(maxWaitDate)) { + else if (LocalDateTime.now().isAfter(maxWaitDateTime)) { throw new AsyncTimeout(uuid); } else { diff --git a/xplan-core/xplan-core-commons/pom.xml b/xplan-core/xplan-core-commons/pom.xml index 12167334884621312f0f03eadee2b2012cfc7665..59d8f78505647a50b93ee8ed0a67a86b0debab6f 100644 --- a/xplan-core/xplan-core-commons/pom.xml +++ b/xplan-core/xplan-core-commons/pom.xml @@ -116,8 +116,9 @@ <scope>test</scope> </dependency> <dependency> - <groupId>com.amazonaws</groupId> - <artifactId>aws-java-sdk-s3</artifactId> + <groupId>software.amazon.awssdk</groupId> + <artifactId>s3</artifactId> + <version>2.30.10</version> </dependency> <dependency> <groupId>org.springframework</groupId> @@ -128,6 +129,10 @@ <artifactId>xmlunit-matchers</artifactId> <scope>test</scope> </dependency> + <dependency> + <groupId>org.springframework.boot</groupId> + <artifactId>spring-boot-autoconfigure</artifactId> + </dependency> </dependencies> </project> \ No newline at end of file diff --git a/xplan-core/xplan-core-commons/src/main/java/de/latlon/xplan/commons/s3/S3Storage.java b/xplan-core/xplan-core-commons/src/main/java/de/latlon/xplan/commons/s3/S3Storage.java index e3ff6f7f61f6877a2fd4b9b454e4c2538678f824..6c7d68d84c861f8fee77d59b3d2409507d00fdc7 100644 --- a/xplan-core/xplan-core-commons/src/main/java/de/latlon/xplan/commons/s3/S3Storage.java +++ b/xplan-core/xplan-core-commons/src/main/java/de/latlon/xplan/commons/s3/S3Storage.java @@ -8,42 +8,50 @@ * it under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. - * + * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * + * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. * #L% */ package de.latlon.xplan.commons.s3; -import static com.amazonaws.services.s3.model.BucketLifecycleConfiguration.ENABLED; - -import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import java.nio.file.Path; import java.util.List; -import com.amazonaws.AmazonServiceException; -import com.amazonaws.services.s3.AmazonS3; -import com.amazonaws.services.s3.model.AmazonS3Exception; -import com.amazonaws.services.s3.model.Bucket; -import com.amazonaws.services.s3.model.BucketLifecycleConfiguration; -import com.amazonaws.services.s3.model.ObjectListing; -import com.amazonaws.services.s3.model.ObjectMetadata; -import com.amazonaws.services.s3.model.PutObjectResult; -import com.amazonaws.services.s3.model.S3Object; -import com.amazonaws.services.s3.model.S3ObjectSummary; -import com.amazonaws.services.s3.model.lifecycle.LifecycleFilter; import de.latlon.xplan.commons.archive.ArchiveEntry; import de.latlon.xplan.commons.archive.XPlanArchiveContentAccess; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import software.amazon.awssdk.awscore.exception.AwsServiceException; +import software.amazon.awssdk.core.ResponseInputStream; +import software.amazon.awssdk.core.sync.RequestBody; +import software.amazon.awssdk.services.s3.S3Client; +import software.amazon.awssdk.services.s3.model.Bucket; +import software.amazon.awssdk.services.s3.model.BucketLifecycleConfiguration; +import software.amazon.awssdk.services.s3.model.CreateBucketRequest; +import software.amazon.awssdk.services.s3.model.DeleteObjectRequest; +import software.amazon.awssdk.services.s3.model.ExpirationStatus; +import software.amazon.awssdk.services.s3.model.GetObjectRequest; +import software.amazon.awssdk.services.s3.model.GetObjectResponse; +import software.amazon.awssdk.services.s3.model.HeadBucketRequest; +import software.amazon.awssdk.services.s3.model.LifecycleExpiration; +import software.amazon.awssdk.services.s3.model.LifecycleRule; +import software.amazon.awssdk.services.s3.model.LifecycleRuleFilter; +import software.amazon.awssdk.services.s3.model.ListObjectsRequest; +import software.amazon.awssdk.services.s3.model.ListObjectsResponse; +import software.amazon.awssdk.services.s3.model.NoSuchBucketException; +import software.amazon.awssdk.services.s3.model.PutBucketLifecycleConfigurationRequest; +import software.amazon.awssdk.services.s3.model.PutObjectRequest; +import software.amazon.awssdk.services.s3.model.PutObjectResponse; +import software.amazon.awssdk.services.s3.model.S3Exception; /** * @author <a href="mailto:goltz@lat-lon.de">Lyn Goltz </a> @@ -53,24 +61,29 @@ public class S3Storage { private static final Logger LOG = LoggerFactory.getLogger(S3Storage.class); - private final AmazonS3 client; + private final S3Client client; private final String bucketName; - public S3Storage(AmazonS3 client, String bucketName) { + public S3Storage(S3Client client, String bucketName) { this.client = client; this.bucketName = bucketName; } public void setBucketExpirationDate(String id, int expirationInDays) throws StorageException { createBucketIfNotExists(); - BucketLifecycleConfiguration bucketLifecycleConfig = new BucketLifecycleConfiguration(); - BucketLifecycleConfiguration.Rule rule = new BucketLifecycleConfiguration.Rule().withId(id) - .withExpirationInDays(expirationInDays) - .withStatus(ENABLED) - .withFilter(new LifecycleFilter()); - bucketLifecycleConfig.withRules(rule); - client.setBucketLifecycleConfiguration(bucketName, bucketLifecycleConfig); + LifecycleRule rule = LifecycleRule.builder() + .id(id) + .expiration(LifecycleExpiration.builder().days(expirationInDays).build()) + .status(ExpirationStatus.ENABLED) + .filter(LifecycleRuleFilter.builder().build()) + .build(); + BucketLifecycleConfiguration bucketLifecycleConfig = BucketLifecycleConfiguration.builder().rules(rule).build(); + PutBucketLifecycleConfigurationRequest lifecycleRequest = PutBucketLifecycleConfigurationRequest.builder() + .bucket(bucketName) + .lifecycleConfiguration(bucketLifecycleConfig) + .build(); + client.putBucketLifecycleConfiguration(lifecycleRequest); } /** @@ -80,18 +93,17 @@ public class S3Storage { * with the passed key was not found */ public de.latlon.xplan.commons.s3.S3Object getObject(String key) throws StorageException { - S3Object object = null; + ResponseInputStream<GetObjectResponse> object = null; try { LOG.info("Get object with key {} from bucket {}.", key, bucketName); - object = client.getObject(bucketName, key); - ObjectMetadata objectMetadata = object.getObjectMetadata(); - S3Metadata s3Metadata = new S3Metadata(object.getKey(), objectMetadata.getContentType(), - objectMetadata.getContentLength()); + object = client.getObject(GetObjectRequest.builder().bucket(bucketName).key(key).build()); + GetObjectResponse response = object.response(); + S3Metadata s3Metadata = new S3Metadata(key, response.contentType(), response.contentLength()); ByteArrayOutputStream bos = new ByteArrayOutputStream(); - object.getObjectContent().transferTo(bos); + object.transferTo(bos); return new de.latlon.xplan.commons.s3.S3Object(s3Metadata, bos.toByteArray()); } - catch (AmazonServiceException | IOException e) { + catch (AwsServiceException | IOException e) { throw new StorageException("Could not get object with key " + key + " from bucket " + bucketName + ".", e); } finally { @@ -108,18 +120,20 @@ public class S3Storage { public S3Metadata getObjectMetadata(String key) throws StorageException { try { LOG.info("Get object metadata with key {} from bucket {}.", key, bucketName); - S3Object object = client.getObject(bucketName, key); - ObjectMetadata objectMetadata = object.getObjectMetadata(); - return new S3Metadata(object.getKey(), objectMetadata.getContentType(), objectMetadata.getContentLength()); + ResponseInputStream<GetObjectResponse> object = client + .getObject(GetObjectRequest.builder().bucket(bucketName).key(key).build()); + GetObjectResponse response = object.response(); + return new S3Metadata(key, response.contentType(), response.contentLength()); } - catch (AmazonServiceException e) { + catch (AwsServiceException e) { throw new StorageException("Could not get object with key " + key + " from bucket " + bucketName + ".", e); } } - public List<S3ObjectSummary> listObjects(String prefix) { - ObjectListing objectsToDelete = client.listObjects(bucketName, prefix); - return objectsToDelete.getObjectSummaries(); + public List<software.amazon.awssdk.services.s3.model.S3Object> listObjects(String prefix) { + ListObjectsResponse objectsToDelete = client + .listObjects(ListObjectsRequest.builder().bucket(bucketName).prefix(prefix).build()); + return objectsToDelete.contents(); } public String insertObject(int planId, String entryName, XPlanArchiveContentAccess archive) @@ -132,24 +146,28 @@ public class S3Storage { String contentType = entry.getContentType(); long contentLength = entry.getContentLength(); InputStream content = archive.retrieveInputStreamFor(entryName); - ObjectMetadata metadata = new ObjectMetadata(); - metadata.setContentLength(contentLength); - metadata.setContentType(contentType); - client.putObject(bucketName, key, content, metadata); + PutObjectRequest putObjectRequest = PutObjectRequest.builder() + .bucket(bucketName) + .key(key) + .contentLength(contentLength) + .contentType(contentType) + .build(); + client.putObject(putObjectRequest, RequestBody.fromInputStream(content, contentLength)); return key; } - catch (AmazonServiceException e) { + catch (AwsServiceException e) { throw new StorageException("Could not insert object with key " + key + " in bucket " + bucketName + ".", e); } } - public PutObjectResult insertObject(String key, Path file) throws StorageException { + public PutObjectResponse insertObject(String key, Path file) throws StorageException { createBucketIfNotExists(); try { LOG.info("Insert object with key {} in bucket {}.", key, bucketName); - return client.putObject(bucketName, key, file.toFile()); + return client.putObject(PutObjectRequest.builder().bucket(bucketName).key(key).build(), + RequestBody.fromFile(file.toFile())); } - catch (AmazonServiceException e) { + catch (AwsServiceException e) { throw new StorageException("Could not insert object with key " + key + " in bucket " + bucketName + ".", e); } } @@ -159,61 +177,65 @@ public class S3Storage { String key = object.getS3Metadata().getKey(); try { LOG.info("Insert object with key {} in bucket {}.", key, bucketName); - ObjectMetadata metadata = new ObjectMetadata(); - metadata.setContentLength(object.getS3Metadata().getContentLength()); - metadata.setContentType(object.getS3Metadata().getContentType()); - ByteArrayInputStream bis = new ByteArrayInputStream(object.getContent()); - client.putObject(bucketName, key, bis, metadata); - } - catch (AmazonServiceException e) { + long contentLength = object.getS3Metadata().getContentLength(); + String contentType = object.getS3Metadata().getContentType(); + PutObjectRequest putObjectRequest = PutObjectRequest.builder() + .bucket(bucketName) + .key(key) + .contentLength(contentLength) + .contentType(contentType) + .build(); + client.putObject(putObjectRequest, RequestBody.fromBytes(object.getContent())); + } + catch (AwsServiceException e) { throw new StorageException("Could not insert object with key " + key + " in bucket " + bucketName + ".", e); } } public void deleteObjects(String prefix) { - List<S3ObjectSummary> objects = listObjects(prefix); - for (S3ObjectSummary object : objects) { + List<software.amazon.awssdk.services.s3.model.S3Object> objects = listObjects(prefix); + for (software.amazon.awssdk.services.s3.model.S3Object object : objects) { deleteObject(object); } } - public void deleteObject(S3ObjectSummary object) { - String key = object.getKey(); + public void deleteObject(software.amazon.awssdk.services.s3.model.S3Object object) { + String key = object.key(); LOG.info("Delete object with key {} from bucket {}.", key, bucketName); - client.deleteObject(bucketName, key); + client.deleteObject(DeleteObjectRequest.builder().bucket(bucketName).key(key).build()); } protected String createKey(int planId, String entry) { return planId + "_" + entry; } - protected Bucket createBucketIfNotExists() throws StorageException { - if (client.doesBucketExistV2(bucketName)) { + protected void createBucketIfNotExists() throws StorageException { + try { + client.headBucket(HeadBucketRequest.builder().bucket(bucketName).build()); LOG.info("Bucket {} already exists.", bucketName); - return getBucket(); } - else { + catch (NoSuchBucketException n) { try { LOG.info("Create bucket with name {}.", bucketName); - return client.createBucket(bucketName); + client.createBucket(CreateBucketRequest.builder().bucket(bucketName).build()); } - catch (AmazonS3Exception e) { + catch (S3Exception e) { throw new StorageException("Could not create bucket", e); } } } public Bucket getBucket() { - List<Bucket> buckets = client.listBuckets(); + List<Bucket> buckets = client.listBuckets().buckets(); for (Bucket bucket : buckets) { - if (bucket.getName().equals(bucketName)) { + if (bucket.name().equals(bucketName)) { return bucket; } } return null; } - private void closeQuietly(S3Object object) { + private void closeQuietly(ResponseInputStream<GetObjectResponse> object) { if (object != null) { try { object.close(); diff --git a/xplan-core/xplan-core-commons/src/main/java/de/latlon/xplan/commons/s3/StorageException.java b/xplan-core/xplan-core-commons/src/main/java/de/latlon/xplan/commons/s3/StorageException.java index c6991a3e75af04b98db89a9210149fc13aba1a2b..975b35d62b027e86126a96dfe7c50c568280675d 100644 --- a/xplan-core/xplan-core-commons/src/main/java/de/latlon/xplan/commons/s3/StorageException.java +++ b/xplan-core/xplan-core-commons/src/main/java/de/latlon/xplan/commons/s3/StorageException.java @@ -20,7 +20,7 @@ */ package de.latlon.xplan.commons.s3; -import com.amazonaws.AmazonServiceException; +import software.amazon.awssdk.awscore.exception.AwsServiceException; /** * @author <a href="mailto:goltz@lat-lon.de">Lyn Goltz </a> @@ -31,8 +31,8 @@ public class StorageException extends Exception { public StorageException(String message, Throwable e) { super(message, e); - if (e instanceof AmazonServiceException) - this.statusCode = ((AmazonServiceException) e).getStatusCode(); + if (e instanceof AwsServiceException) + this.statusCode = ((AwsServiceException) e).awsErrorDetails().sdkHttpResponse().statusCode(); } public StorageException(String message, int statusCode) { diff --git a/xplan-core/xplan-core-commons/src/main/java/de/latlon/xplan/commons/s3/config/AmazonS3ReadOnlyContext.java b/xplan-core/xplan-core-commons/src/main/java/de/latlon/xplan/commons/s3/config/AmazonS3ReadOnlyContext.java index f89d92ad9d486d66a038c7619f9ee1ffa9f16438..512e200a10767d13b92f42f6e1a0c773b77ba034 100644 --- a/xplan-core/xplan-core-commons/src/main/java/de/latlon/xplan/commons/s3/config/AmazonS3ReadOnlyContext.java +++ b/xplan-core/xplan-core-commons/src/main/java/de/latlon/xplan/commons/s3/config/AmazonS3ReadOnlyContext.java @@ -8,18 +8,21 @@ * it under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. - * + * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * + * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. * #L% */ package de.latlon.xplan.commons.s3.config; +import java.net.URI; +import java.net.URISyntaxException; + import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Value; @@ -27,13 +30,11 @@ import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Profile; - -import com.amazonaws.auth.AWSCredentials; -import com.amazonaws.auth.AWSStaticCredentialsProvider; -import com.amazonaws.auth.BasicAWSCredentials; -import com.amazonaws.client.builder.AwsClientBuilder; -import com.amazonaws.services.s3.AmazonS3; -import com.amazonaws.services.s3.AmazonS3ClientBuilder; +import software.amazon.awssdk.auth.credentials.AwsBasicCredentials; +import software.amazon.awssdk.auth.credentials.AwsCredentialsProvider; +import software.amazon.awssdk.auth.credentials.StaticCredentialsProvider; +import software.amazon.awssdk.regions.Region; +import software.amazon.awssdk.services.s3.S3Client; /** * Spring configuration for using AWS S3 as a storage. @@ -44,38 +45,34 @@ import com.amazonaws.services.s3.AmazonS3ClientBuilder; */ @Configuration @ComponentScan("de.latlon.xplan.manager.storage.s3.listener") -@Profile("!test") +@Profile({ "!test" }) public class AmazonS3ReadOnlyContext { private static final Logger LOG = LoggerFactory.getLogger(AmazonS3ReadOnlyContext.class); - @Bean(destroyMethod = "shutdown") - public AmazonS3 s3Client(AWSCredentials credentials, + @Bean(destroyMethod = "close") + public S3Client s3Client(AwsCredentialsProvider credentialsProvider, @Value("${xplanbox.s3.region:#{environment.XPLAN_S3_REGION}}") String region, - @Value("${xplanbox.s3.endpoint.url:#{environment.XPLAN_S3_ENDPOINT}}") String endpointUrl) { + @Value("${xplanbox.s3.endpoint.url:#{environment.XPLAN_S3_ENDPOINT}}") String endpointUrl) + throws URISyntaxException { - // TODO refactoring if/else to @ConditionalOnExpression with SpringBoot into 2 - // SpringBeans - AmazonS3ClientBuilder builder = AmazonS3ClientBuilder.standard() - .withCredentials(new AWSStaticCredentialsProvider(credentials)); if (endpointUrl == null || endpointUrl.isEmpty()) { LOG.info("Using S3 region {}", region); - builder.withRegion(region); - } - else { - LOG.info("Using S3 url {} (region {})", endpointUrl); - AwsClientBuilder.EndpointConfiguration endpoint = new AwsClientBuilder.EndpointConfiguration(endpointUrl, - region); - builder.withEndpointConfiguration(endpoint); + return S3Client.builder().credentialsProvider(credentialsProvider).region(Region.of(region)).build(); } - return builder.build(); + LOG.info("Using S3 url {} (region {})", endpointUrl); + return S3Client.builder() + .credentialsProvider(credentialsProvider) + .region(Region.of(region)) + .endpointOverride(new URI(endpointUrl)) + .build(); } @Bean - public AWSCredentials credentials( + public AwsCredentialsProvider credentialsProvider( @Value("${xplanbox.s3.accessKeyId:#{environment.XPLAN_S3_ACCESS_KEY}}") String accessKeyId, @Value("${xplanbox.s3.secretKey:#{environment.XPLAN_S3_SECRET_ACCESS_KEY}}") String secretKey) { - return new BasicAWSCredentials(accessKeyId, secretKey); + return StaticCredentialsProvider.create(AwsBasicCredentials.create(accessKeyId, secretKey)); } } diff --git a/xplan-core/xplan-core-manager/pom.xml b/xplan-core/xplan-core-manager/pom.xml index fb90bc97e43119155b10bbd03d19afd2a7e3aabb..338fe199ba3f3edc789d018f89bb75f87f9b4d1c 100644 --- a/xplan-core/xplan-core-manager/pom.xml +++ b/xplan-core/xplan-core-manager/pom.xml @@ -126,8 +126,9 @@ </dependency> <!-- AWS SDK For Java --> <dependency> - <groupId>com.amazonaws</groupId> - <artifactId>aws-java-sdk-s3</artifactId> + <groupId>software.amazon.awssdk</groupId> + <artifactId>s3</artifactId> + <version>2.30.10</version> </dependency> <dependency> <groupId>com.github.spotbugs</groupId> diff --git a/xplan-core/xplan-core-manager/src/main/java/de/latlon/xplan/manager/document/config/AmazonS3DocumentStorageContext.java b/xplan-core/xplan-core-manager/src/main/java/de/latlon/xplan/manager/document/config/AmazonS3DocumentStorageContext.java index 8e36037cbdef35cd9f2dc29198f646a4f4e40cac..6d839287f2e7bf4a81b49e5f0b74745caecffec0 100644 --- a/xplan-core/xplan-core-manager/src/main/java/de/latlon/xplan/manager/document/config/AmazonS3DocumentStorageContext.java +++ b/xplan-core/xplan-core-manager/src/main/java/de/latlon/xplan/manager/document/config/AmazonS3DocumentStorageContext.java @@ -22,7 +22,6 @@ package de.latlon.xplan.manager.document.config; import java.util.Optional; -import com.amazonaws.services.s3.AmazonS3; import de.latlon.xplan.manager.document.DocumentStorage; import de.latlon.xplan.manager.document.XPlanDocumentManager; import de.latlon.xplan.manager.document.s3.S3DocumentStorage; @@ -31,6 +30,7 @@ import org.springframework.beans.factory.annotation.Value; import org.springframework.context.ApplicationEventPublisher; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import software.amazon.awssdk.services.s3.S3Client; /** * @author <a href="mailto:goltz@lat-lon.de">Lyn Goltz </a> @@ -50,7 +50,7 @@ public class AmazonS3DocumentStorageContext { } @Bean - public S3DocumentStorage documentStorage(AmazonS3 s3Client, + public S3DocumentStorage documentStorage(S3Client s3Client, @Value("${xplanbox.s3.bucketName:#{environment.XPLAN_S3_BUCKET_ATTACHMENTS}}") String bucketName) { return new S3DocumentStorage(s3Client, bucketName); } diff --git a/xplan-core/xplan-core-manager/src/main/java/de/latlon/xplan/manager/document/s3/S3DocumentStorage.java b/xplan-core/xplan-core-manager/src/main/java/de/latlon/xplan/manager/document/s3/S3DocumentStorage.java index 91ae70d8dc133e236503154cff3c7b94e63fc1e0..fb9c2b724319314a2343ee2077f251673a1741a9 100644 --- a/xplan-core/xplan-core-manager/src/main/java/de/latlon/xplan/manager/document/s3/S3DocumentStorage.java +++ b/xplan-core/xplan-core-manager/src/main/java/de/latlon/xplan/manager/document/s3/S3DocumentStorage.java @@ -20,10 +20,10 @@ */ package de.latlon.xplan.manager.document.s3; -import com.amazonaws.services.s3.AmazonS3; import de.latlon.xplan.commons.archive.XPlanArchive; import de.latlon.xplan.manager.document.DocumentStorage; import de.latlon.xplan.manager.storage.StorageEvent; +import software.amazon.awssdk.services.s3.S3Client; import de.latlon.xplan.commons.s3.S3Object; import de.latlon.xplan.commons.s3.S3Storage; import de.latlon.xplan.commons.s3.StorageException; @@ -40,7 +40,7 @@ import java.util.List; */ public class S3DocumentStorage extends S3Storage implements DocumentStorage { - public S3DocumentStorage(AmazonS3 client, String bucketName) { + public S3DocumentStorage(S3Client client, String bucketName) { super(client, bucketName); } diff --git a/xplan-core/xplan-core-manager/src/main/java/de/latlon/xplan/manager/storage/s3/S3StorageCleanUpManager.java b/xplan-core/xplan-core-manager/src/main/java/de/latlon/xplan/manager/storage/s3/S3StorageCleanUpManager.java index 5b12362b2abf2edb511e5c1beb5134576a02d4a4..e2f838732cd42412cb6dda52727108a233566be4 100644 --- a/xplan-core/xplan-core-manager/src/main/java/de/latlon/xplan/manager/storage/s3/S3StorageCleanUpManager.java +++ b/xplan-core/xplan-core-manager/src/main/java/de/latlon/xplan/manager/storage/s3/S3StorageCleanUpManager.java @@ -20,15 +20,14 @@ */ package de.latlon.xplan.manager.storage.s3; -import com.amazonaws.services.s3.AmazonS3; -import com.amazonaws.services.s3.model.S3ObjectSummary; +import java.util.List; + import de.latlon.xplan.commons.s3.S3Object; import de.latlon.xplan.commons.s3.S3Storage; +import de.latlon.xplan.commons.s3.StorageException; import de.latlon.xplan.manager.storage.StorageCleanUpManager; import de.latlon.xplan.manager.storage.StorageEvent; -import de.latlon.xplan.commons.s3.StorageException; - -import java.util.List; +import software.amazon.awssdk.services.s3.S3Client; /** * @author <a href="mailto:goltz@lat-lon.de">Lyn Goltz </a> @@ -36,19 +35,19 @@ import java.util.List; */ public class S3StorageCleanUpManager extends S3Storage implements StorageCleanUpManager { - public S3StorageCleanUpManager(AmazonS3 client, String bucketName) { + public S3StorageCleanUpManager(S3Client client, String bucketName) { super(client, bucketName); } @Override public void deleteAll(String id, StorageEvent storageEvent) throws StorageException { - List<S3ObjectSummary> s3ObjectSummaries = listObjects(id + "_"); - for (S3ObjectSummary objectSummary : s3ObjectSummaries) { - String key = objectSummary.getKey(); + List<software.amazon.awssdk.services.s3.model.S3Object> s3Objects = listObjects(id + "_"); + for (software.amazon.awssdk.services.s3.model.S3Object s3object : s3Objects) { + String key = s3object.key(); S3Object object = getObject(key); if (object != null) storageEvent.addDeletedKey(object); - deleteObject(objectSummary); + deleteObject(s3object); } } diff --git a/xplan-core/xplan-core-manager/src/main/java/de/latlon/xplan/manager/storage/s3/config/AmazonS3TransactionalContext.java b/xplan-core/xplan-core-manager/src/main/java/de/latlon/xplan/manager/storage/s3/config/AmazonS3TransactionalContext.java index 03cce2384c9dd4aad9e690988047339260dd8ebd..2ff1e6b637a5a7f0c65787f26500fb1dab622467 100644 --- a/xplan-core/xplan-core-manager/src/main/java/de/latlon/xplan/manager/storage/s3/config/AmazonS3TransactionalContext.java +++ b/xplan-core/xplan-core-manager/src/main/java/de/latlon/xplan/manager/storage/s3/config/AmazonS3TransactionalContext.java @@ -20,7 +20,6 @@ */ package de.latlon.xplan.manager.storage.s3.config; -import com.amazonaws.services.s3.AmazonS3; import de.latlon.xplan.commons.s3.S3Storage; import de.latlon.xplan.commons.s3.config.AmazonS3ReadOnlyContext; import de.latlon.xplan.manager.storage.StorageCleanUpManager; @@ -29,6 +28,7 @@ import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Import; +import software.amazon.awssdk.services.s3.S3Client; /** * Spring configuration for using AWS S3 as a storage. @@ -42,13 +42,13 @@ import org.springframework.context.annotation.Import; public class AmazonS3TransactionalContext { @Bean - public StorageCleanUpManager storageCleanUpManager(AmazonS3 s3Client, + public StorageCleanUpManager storageCleanUpManager(S3Client s3Client, @Value("${xplanbox.s3.bucketName:#{environment.XPLAN_S3_BUCKET_ATTACHMENTS}}") String bucketName) { return new S3StorageCleanUpManager(s3Client, bucketName); } @Bean - public S3Storage rollbackStorage(AmazonS3 s3Client, + public S3Storage rollbackStorage(S3Client s3Client, @Value("${xplanbox.s3.bucketName:#{environment.XPLAN_S3_BUCKET_ATTACHMENTS}}") String bucketName) { return new S3Storage(s3Client, bucketName); } diff --git a/xplan-core/xplan-core-manager/src/main/java/de/latlon/xplan/manager/wmsconfig/raster/storage/s3/S3RasterStorage.java b/xplan-core/xplan-core-manager/src/main/java/de/latlon/xplan/manager/wmsconfig/raster/storage/s3/S3RasterStorage.java index 3466cb120c573f9487d0b75e0530a8c49de33897..f53fae378d7da4cf88a03710864151298b0a5a16 100644 --- a/xplan-core/xplan-core-manager/src/main/java/de/latlon/xplan/manager/wmsconfig/raster/storage/s3/S3RasterStorage.java +++ b/xplan-core/xplan-core-manager/src/main/java/de/latlon/xplan/manager/wmsconfig/raster/storage/s3/S3RasterStorage.java @@ -20,7 +20,6 @@ */ package de.latlon.xplan.manager.wmsconfig.raster.storage.s3; -import com.amazonaws.services.s3.AmazonS3; import de.latlon.xplan.commons.archive.XPlanArchiveContentAccess; import de.latlon.xplan.manager.storage.StorageEvent; import de.latlon.xplan.commons.s3.S3Object; @@ -28,6 +27,7 @@ import de.latlon.xplan.commons.s3.S3Storage; import de.latlon.xplan.manager.wmsconfig.raster.storage.RasterStorage; import de.latlon.xplan.commons.s3.StorageException; import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; +import software.amazon.awssdk.services.s3.S3Client; /** * {@link RasterStorage} implementation storing and deleting raster files in a S3 bucket. @@ -37,7 +37,7 @@ import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; */ public class S3RasterStorage extends S3Storage implements RasterStorage { - public S3RasterStorage(AmazonS3 client, String bucketName) { + public S3RasterStorage(S3Client client, String bucketName) { super(client, bucketName); } diff --git a/xplan-core/xplan-core-manager/src/main/java/de/latlon/xplan/manager/wmsconfig/raster/storage/s3/config/AmazonS3RasterStorageContext.java b/xplan-core/xplan-core-manager/src/main/java/de/latlon/xplan/manager/wmsconfig/raster/storage/s3/config/AmazonS3RasterStorageContext.java index 8d35767ff076510adedc86eb8e2fc34ee21b121d..6c00e40ebeb1f434829681a48bb0101b69b09501 100644 --- a/xplan-core/xplan-core-manager/src/main/java/de/latlon/xplan/manager/wmsconfig/raster/storage/s3/config/AmazonS3RasterStorageContext.java +++ b/xplan-core/xplan-core-manager/src/main/java/de/latlon/xplan/manager/wmsconfig/raster/storage/s3/config/AmazonS3RasterStorageContext.java @@ -20,13 +20,13 @@ */ package de.latlon.xplan.manager.wmsconfig.raster.storage.s3.config; -import com.amazonaws.services.s3.AmazonS3; import de.latlon.xplan.manager.storage.s3.config.AmazonS3TransactionalContext; import de.latlon.xplan.manager.wmsconfig.raster.storage.s3.S3RasterStorage; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Import; +import software.amazon.awssdk.services.s3.S3Client; /** * Spring configuration for using AWS S3 as a storage for raster data. This requires @@ -42,7 +42,7 @@ import org.springframework.context.annotation.Import; public class AmazonS3RasterStorageContext { @Bean - public S3RasterStorage rasterStorage(AmazonS3 s3Client, + public S3RasterStorage rasterStorage(S3Client s3Client, @Value("${xplanbox.s3.bucketName:#{environment.XPLAN_S3_BUCKET_ATTACHMENTS}}") String bucketName) { return new S3RasterStorage(s3Client, bucketName); } diff --git a/xplan-core/xplan-core-manager/src/test/java/de/latlon/xplan/manager/document/s3/S3DocumentStorageIT.java b/xplan-core/xplan-core-manager/src/test/java/de/latlon/xplan/manager/document/s3/S3DocumentStorageIT.java index 41964afc48ec1e7379583d17b6b8736b003e8466..b4b8028325f72a2474d87757598d65cc2f96ca5b 100644 --- a/xplan-core/xplan-core-manager/src/test/java/de/latlon/xplan/manager/document/s3/S3DocumentStorageIT.java +++ b/xplan-core/xplan-core-manager/src/test/java/de/latlon/xplan/manager/document/s3/S3DocumentStorageIT.java @@ -29,6 +29,12 @@ import java.io.InputStream; import java.util.Collections; import java.util.List; +import de.latlon.xplan.commons.archive.XPlanArchive; +import de.latlon.xplan.commons.archive.XPlanArchiveCreator; +import de.latlon.xplan.commons.s3.StorageException; +import de.latlon.xplan.manager.document.config.AmazonS3DocumentStorageContext; +import de.latlon.xplan.manager.storage.StorageEvent; +import de.latlon.xplan.manager.storage.s3.config.TestS3Context; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.springframework.beans.factory.annotation.Autowired; @@ -37,13 +43,6 @@ import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.TestPropertySource; import org.springframework.test.context.junit.jupiter.SpringExtension; -import de.latlon.xplan.commons.archive.XPlanArchive; -import de.latlon.xplan.commons.archive.XPlanArchiveCreator; -import de.latlon.xplan.commons.s3.StorageException; -import de.latlon.xplan.manager.document.config.AmazonS3DocumentStorageContext; -import de.latlon.xplan.manager.storage.StorageEvent; -import de.latlon.xplan.manager.storage.s3.config.AmazonS3TestContext; - /** * ATTENTION: Executing this test class can run up the bill for the AWS account * configured! Ensure that the S3 client is using a free account or is substituted by a @@ -55,8 +54,8 @@ import de.latlon.xplan.manager.storage.s3.config.AmazonS3TestContext; * @author <a href="mailto:goltz@lat-lon.de">Lyn Goltz </a> * @author <a href="mailto:friebe@lat-lon.de">Torsten Friebe</a> */ -@ContextConfiguration(classes = { AmazonS3DocumentStorageContext.class, AmazonS3TestContext.class }) -@ActiveProfiles({ "mock" }) +@ContextConfiguration(classes = { AmazonS3DocumentStorageContext.class, TestS3Context.class }) +@ActiveProfiles({ "mock", "test" }) @TestPropertySource("classpath:s3Mock.properties") @ExtendWith(SpringExtension.class) class S3DocumentStorageIT { diff --git a/xplan-core/xplan-core-manager/src/test/java/de/latlon/xplan/manager/storage/s3/S3StorageCleanUpManagerTest.java b/xplan-core/xplan-core-manager/src/test/java/de/latlon/xplan/manager/storage/s3/S3StorageCleanUpManagerTest.java index 9caecd3db654d699bb3fabab50425a3efa9fc547..f64b4b9ed7555485839429cc6b2ca5aa75da80d3 100644 --- a/xplan-core/xplan-core-manager/src/test/java/de/latlon/xplan/manager/storage/s3/S3StorageCleanUpManagerTest.java +++ b/xplan-core/xplan-core-manager/src/test/java/de/latlon/xplan/manager/storage/s3/S3StorageCleanUpManagerTest.java @@ -8,39 +8,44 @@ * it under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. - * + * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * + * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. * #L% */ package de.latlon.xplan.manager.storage.s3; -import com.amazonaws.services.s3.AmazonS3; -import com.amazonaws.services.s3.model.ObjectListing; -import com.amazonaws.services.s3.model.ObjectMetadata; -import com.amazonaws.services.s3.model.S3Object; -import com.amazonaws.services.s3.model.S3ObjectInputStream; -import com.amazonaws.services.s3.model.S3ObjectSummary; -import de.latlon.xplan.manager.storage.StorageEvent; -import org.junit.jupiter.api.Test; -import de.latlon.xplan.commons.s3.StorageException; -import org.mockito.ArgumentCaptor; - -import java.util.Collections; -import java.util.List; - import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; +import java.util.Collections; +import java.util.List; + +import de.latlon.xplan.commons.s3.StorageException; +import de.latlon.xplan.manager.storage.StorageEvent; +import org.junit.jupiter.api.Test; +import org.mockito.ArgumentCaptor; +import software.amazon.awssdk.core.ResponseInputStream; +import software.amazon.awssdk.services.s3.S3Client; +import software.amazon.awssdk.services.s3.model.DeleteObjectRequest; +import software.amazon.awssdk.services.s3.model.DeleteObjectResponse; +import software.amazon.awssdk.services.s3.model.GetObjectRequest; +import software.amazon.awssdk.services.s3.model.GetObjectResponse; +import software.amazon.awssdk.services.s3.model.ListObjectsRequest; +import software.amazon.awssdk.services.s3.model.ListObjectsResponse; +import software.amazon.awssdk.services.s3.model.S3Object; + /** * @author <a href="mailto:goltz@lat-lon.de">Lyn Goltz </a> */ @@ -50,29 +55,29 @@ class S3StorageCleanUpManagerTest { @Test void deleteRasterFiles() throws StorageException { - AmazonS3 client = spy(AmazonS3.class); - ObjectListing objectListing = mock(ObjectListing.class); - S3Object object = mock(S3Object.class); - when(object.getObjectContent()).thenReturn(mock(S3ObjectInputStream.class)); - ObjectMetadata objectMetadata = mock(ObjectMetadata.class); - when(objectMetadata.getContentType()).thenReturn("image/png"); - when(objectMetadata.getContentLength()).thenReturn(90l); - when(object.getObjectMetadata()).thenReturn(objectMetadata); - when(object.getKey()).thenReturn("1_test.png"); - when(client.listObjects(eq(BUCKET_NAME), eq("1_"))).thenReturn(objectListing); - when(client.getObject(eq(BUCKET_NAME), eq("1_test.png"))).thenReturn(object); + S3Client client = spy(S3Client.class); + ListObjectsResponse objectListing = mock(ListObjectsResponse.class); + doReturn(objectListing).when(client) + .listObjects(eq(ListObjectsRequest.builder().bucket(BUCKET_NAME).prefix("1_").build())); + ResponseInputStream<GetObjectResponse> objectStream = mock(ResponseInputStream.class); + GetObjectResponse getObjectResponse = mock(GetObjectResponse.class); + when(getObjectResponse.contentType()).thenReturn("image/png"); + when(getObjectResponse.contentLength()).thenReturn(90l); + when(objectStream.response()).thenReturn(getObjectResponse); + doReturn(objectStream).when(client).getObject(any(GetObjectRequest.class)); + doReturn(DeleteObjectResponse.builder().build()).when(client).deleteObject(any(DeleteObjectRequest.class)); - S3ObjectSummary objectToDelete = mock(S3ObjectSummary.class); - when(objectToDelete.getKey()).thenReturn("1_test.png"); - List<S3ObjectSummary> objectSummaries = Collections.singletonList(objectToDelete); - when(objectListing.getObjectSummaries()).thenReturn(objectSummaries); + S3Object objectToDelete = mock(S3Object.class); + when(objectToDelete.key()).thenReturn("1_test.png"); + List<S3Object> objectSummaries = Collections.singletonList(objectToDelete); + when(objectListing.contents()).thenReturn(objectSummaries); S3StorageCleanUpManager s3RasterStorage = new S3StorageCleanUpManager(client, BUCKET_NAME); StorageEvent storageEvent = mock(StorageEvent.class); s3RasterStorage.deleteAll("1", storageEvent); - verify(client).listObjects(BUCKET_NAME, "1_"); - verify(client).deleteObject(BUCKET_NAME, "1_test.png"); + verify(client).listObjects(ListObjectsRequest.builder().bucket(BUCKET_NAME).prefix("1_").build()); + verify(client).deleteObject(DeleteObjectRequest.builder().bucket(BUCKET_NAME).key("1_test.png").build()); ArgumentCaptor<de.latlon.xplan.commons.s3.S3Object> argument = ArgumentCaptor .forClass(de.latlon.xplan.commons.s3.S3Object.class); verify(storageEvent).addDeletedKey(argument.capture()); diff --git a/xplan-core/xplan-core-manager/src/test/java/de/latlon/xplan/manager/storage/s3/S3StorageTestManual.java b/xplan-core/xplan-core-manager/src/test/java/de/latlon/xplan/manager/storage/s3/S3StorageTestManual.java index fb8658f4a99485ec484cf4bd1a06efbf76a87188..372065075fc551440e1e2004ac1ddfe012b2bc61 100644 --- a/xplan-core/xplan-core-manager/src/test/java/de/latlon/xplan/manager/storage/s3/S3StorageTestManual.java +++ b/xplan-core/xplan-core-manager/src/test/java/de/latlon/xplan/manager/storage/s3/S3StorageTestManual.java @@ -40,7 +40,7 @@ import de.latlon.xplan.commons.s3.S3Metadata; import de.latlon.xplan.commons.s3.S3Object; import de.latlon.xplan.commons.s3.S3Storage; import de.latlon.xplan.commons.s3.StorageException; -import de.latlon.xplan.manager.storage.s3.config.AmazonS3TestContext; +import de.latlon.xplan.manager.storage.s3.config.TestS3Context; import de.latlon.xplan.manager.storage.s3.config.S3StorageTestContext; /** @@ -53,7 +53,7 @@ import de.latlon.xplan.manager.storage.s3.config.S3StorageTestContext; * * @author <a href="mailto:goltz@lat-lon.de">Lyn Goltz </a> */ -@ContextConfiguration(classes = { AmazonS3TestContext.class, S3StorageTestContext.class }) +@ContextConfiguration(classes = { TestS3Context.class, S3StorageTestContext.class }) @ActiveProfiles({ "mock" }) @TestPropertySource("classpath:s3Mock.properties") @ExtendWith(SpringExtension.class) diff --git a/xplan-core/xplan-core-manager/src/test/java/de/latlon/xplan/manager/storage/s3/config/S3StorageTestContext.java b/xplan-core/xplan-core-manager/src/test/java/de/latlon/xplan/manager/storage/s3/config/S3StorageTestContext.java index cfbc7127d40ed5d1206ff2d24293684ed962d9c9..75095c66124eef802ff62f9a8282973c2ee2b94a 100644 --- a/xplan-core/xplan-core-manager/src/test/java/de/latlon/xplan/manager/storage/s3/config/S3StorageTestContext.java +++ b/xplan-core/xplan-core-manager/src/test/java/de/latlon/xplan/manager/storage/s3/config/S3StorageTestContext.java @@ -20,11 +20,11 @@ */ package de.latlon.xplan.manager.storage.s3.config; -import com.amazonaws.services.s3.AmazonS3; import de.latlon.xplan.commons.s3.S3Storage; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import software.amazon.awssdk.services.s3.S3Client; /** * @author <a href="mailto:goltz@lat-lon.de">Lyn Goltz </a> @@ -33,7 +33,7 @@ import org.springframework.context.annotation.Configuration; public class S3StorageTestContext { @Bean - public S3Storage rollbackStorage(AmazonS3 s3Client, + public S3Storage rollbackStorage(S3Client s3Client, @Value("${xplanbox.s3.bucketName:#{environment.XPLAN_S3_BUCKET_ATTACHMENTS}}") String bucketName) { return new S3Storage(s3Client, bucketName); } diff --git a/xplan-core/xplan-core-manager/src/test/java/de/latlon/xplan/manager/storage/s3/config/AmazonS3TestContext.java b/xplan-core/xplan-core-manager/src/test/java/de/latlon/xplan/manager/storage/s3/config/TestS3Context.java similarity index 61% rename from xplan-core/xplan-core-manager/src/test/java/de/latlon/xplan/manager/storage/s3/config/AmazonS3TestContext.java rename to xplan-core/xplan-core-manager/src/test/java/de/latlon/xplan/manager/storage/s3/config/TestS3Context.java index 53a71759087c604198f7674aee798e0376c3a7b2..58b21cc206a17898376417cc9354d98779add0ed 100644 --- a/xplan-core/xplan-core-manager/src/test/java/de/latlon/xplan/manager/storage/s3/config/AmazonS3TestContext.java +++ b/xplan-core/xplan-core-manager/src/test/java/de/latlon/xplan/manager/storage/s3/config/TestS3Context.java @@ -8,35 +8,36 @@ * it under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. - * + * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * + * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. * #L% */ package de.latlon.xplan.manager.storage.s3.config; -import jakarta.annotation.PreDestroy; +import static software.amazon.awssdk.regions.Region.EU_CENTRAL_1; + +import java.net.URI; +import java.net.URISyntaxException; -import org.springframework.beans.factory.annotation.Autowired; +import io.findify.s3mock.S3Mock; +import jakarta.annotation.PreDestroy; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Primary; import org.springframework.context.annotation.Profile; import org.springframework.test.util.TestSocketUtils; - -import com.amazonaws.auth.AWSStaticCredentialsProvider; -import com.amazonaws.auth.AnonymousAWSCredentials; -import com.amazonaws.client.builder.AwsClientBuilder; -import com.amazonaws.services.s3.AmazonS3; -import com.amazonaws.services.s3.AmazonS3ClientBuilder; - -import io.findify.s3mock.S3Mock; +import software.amazon.awssdk.auth.credentials.AwsBasicCredentials; +import software.amazon.awssdk.auth.credentials.StaticCredentialsProvider; +import software.amazon.awssdk.services.s3.S3Client; +import software.amazon.awssdk.services.s3.S3Configuration; +import software.amazon.awssdk.services.s3.model.CreateBucketRequest; /** * Spring Configuration to enable usage of mock objects for integration tests. @@ -45,20 +46,18 @@ import io.findify.s3mock.S3Mock; * @author <a href="mailto:friebe@lat-lon.de">Torsten Friebe</a> */ @Configuration -public class AmazonS3TestContext { +public class TestS3Context { - @Autowired(required = false) - private S3Mock s3Mock; + private final int port = TestSocketUtils.findAvailableTcpPort(); - @Autowired - private AmazonS3 s3TestClient; + private S3Client s3TestClient; - private final int port = TestSocketUtils.findAvailableTcpPort(); + private S3Mock s3Mock; @Bean @Profile("mock") public S3Mock s3Mock() { - S3Mock s3Mock = new S3Mock.Builder().withPort(port).withInMemoryBackend().build(); + this.s3Mock = new S3Mock.Builder().withPort(port).withInMemoryBackend().build(); s3Mock.start(); return s3Mock; } @@ -66,23 +65,24 @@ public class AmazonS3TestContext { @Bean @Primary @Profile("mock") - public AmazonS3 s3TestClient(@Value("${xplanbox.s3.region}") String signingRegion, - @Value("${xplanbox.s3.bucketName}") String bucketName, @Value("${xplanbox.s3.endpoint.url}") String url) { - - AwsClientBuilder.EndpointConfiguration endpoint = new AwsClientBuilder.EndpointConfiguration(url + ":" + port, - signingRegion); - AmazonS3 client = AmazonS3ClientBuilder.standard() - .withPathStyleAccessEnabled(true) - .withEndpointConfiguration(endpoint) - .withCredentials(new AWSStaticCredentialsProvider(new AnonymousAWSCredentials())) + public S3Client s3Client(S3Mock s3Mock, @Value("${xplanbox.s3.bucketName}") String bucketName) + throws URISyntaxException { + URI endpoint = new URI("http://localhost:" + port); + S3Client client = S3Client.builder() + .serviceConfiguration(S3Configuration.builder().pathStyleAccessEnabled(true).build()) + .endpointOverride(endpoint) + .credentialsProvider( + StaticCredentialsProvider.create(AwsBasicCredentials.create("accessKeyId", "secretKey"))) + .region(EU_CENTRAL_1) .build(); - client.createBucket(bucketName); + client.createBucket(CreateBucketRequest.builder().bucket(bucketName).build()); + s3TestClient = client; return client; } @PreDestroy public void shutdown() { - s3TestClient.shutdown(); + s3TestClient.close(); if (s3Mock != null) { s3Mock.stop(); } diff --git a/xplan-core/xplan-core-manager/src/test/java/de/latlon/xplan/manager/wmsconfig/raster/storage/s3/S3RasterStorageTest.java b/xplan-core/xplan-core-manager/src/test/java/de/latlon/xplan/manager/wmsconfig/raster/storage/s3/S3RasterStorageTest.java index c4b52373d7af2bfd80f0923ceb0c70dc1d3ada6c..3551e9671d0f1a188ec9143521b3040f67fdcb12 100644 --- a/xplan-core/xplan-core-manager/src/test/java/de/latlon/xplan/manager/wmsconfig/raster/storage/s3/S3RasterStorageTest.java +++ b/xplan-core/xplan-core-manager/src/test/java/de/latlon/xplan/manager/wmsconfig/raster/storage/s3/S3RasterStorageTest.java @@ -8,12 +8,12 @@ * it under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. - * + * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * + * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. * #L% @@ -22,20 +22,39 @@ package de.latlon.xplan.manager.wmsconfig.raster.storage.s3; import static org.assertj.core.api.Assertions.assertThat; import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.mockito.Mockito.*; +import static org.mockito.Mockito.any; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.eq; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; -import java.io.InputStream; +import java.io.ByteArrayInputStream; import java.util.Collections; import java.util.List; -import com.amazonaws.services.s3.AmazonS3; -import com.amazonaws.services.s3.model.*; import de.latlon.xplan.commons.archive.ArchiveEntry; import de.latlon.xplan.commons.archive.XPlanArchiveContentAccess; import de.latlon.xplan.commons.s3.StorageException; import de.latlon.xplan.manager.storage.StorageEvent; import org.junit.jupiter.api.Test; import org.mockito.ArgumentCaptor; +import software.amazon.awssdk.core.ResponseInputStream; +import software.amazon.awssdk.core.sync.RequestBody; +import software.amazon.awssdk.services.s3.S3Client; +import software.amazon.awssdk.services.s3.model.DeleteObjectRequest; +import software.amazon.awssdk.services.s3.model.DeleteObjectResponse; +import software.amazon.awssdk.services.s3.model.GetObjectRequest; +import software.amazon.awssdk.services.s3.model.GetObjectResponse; +import software.amazon.awssdk.services.s3.model.HeadBucketRequest; +import software.amazon.awssdk.services.s3.model.HeadBucketResponse; +import software.amazon.awssdk.services.s3.model.ListObjectsRequest; +import software.amazon.awssdk.services.s3.model.ListObjectsResponse; +import software.amazon.awssdk.services.s3.model.PutObjectRequest; +import software.amazon.awssdk.services.s3.model.PutObjectResponse; +import software.amazon.awssdk.services.s3.model.S3Object; /** * @author <a href="mailto:goltz@lat-lon.de">Lyn Goltz </a> @@ -46,46 +65,55 @@ class S3RasterStorageTest { @Test void testAddRasterFile() throws StorageException { - AmazonS3 client = spy(AmazonS3.class); + S3Client client = createS3ClientSpy(); S3RasterStorage s3RasterStorage = new S3RasterStorage(client, BUCKET_NAME); XPlanArchiveContentAccess archive = mockArchive(); StorageEvent storageEvent = mock(StorageEvent.class); String key = s3RasterStorage.addRasterFile(1, "test.png", "test.png.aux.xml", archive, storageEvent); - ArgumentCaptor<String> captor = ArgumentCaptor.forClass(String.class); + + ArgumentCaptor<HeadBucketRequest> headBucketRequestCaptor = ArgumentCaptor.forClass(HeadBucketRequest.class); + ArgumentCaptor<PutObjectRequest> putObjectRequestCaptor = ArgumentCaptor.forClass(PutObjectRequest.class); + assertEquals("1_test.png", key); - verify(client, times(2)).doesBucketExistV2(eq(BUCKET_NAME)); - verify(client, times(2)).putObject(eq(BUCKET_NAME), captor.capture(), nullable(InputStream.class), - any(ObjectMetadata.class)); - assertThat(captor.getAllValues()).contains("1_test.png", "1_test.png.aux.xml"); + + verify(client, times(2)).headBucket(headBucketRequestCaptor.capture()); + verify(client, times(2)).putObject(putObjectRequestCaptor.capture(), any(RequestBody.class)); + assertThat(headBucketRequestCaptor.getAllValues()).map(HeadBucketRequest::bucket) + .containsExactlyInAnyOrder(BUCKET_NAME, BUCKET_NAME); + assertThat(putObjectRequestCaptor.getAllValues()).map(PutObjectRequest::bucket) + .contains(BUCKET_NAME, BUCKET_NAME); + assertThat(putObjectRequestCaptor.getAllValues()).map(PutObjectRequest::key) + .contains("1_test.png", "1_test.png.aux.xml"); verify(storageEvent).addInsertedKey(eq("1_test.png")); } @Test void testDeleteRasterFile() throws StorageException { - AmazonS3 client = spy(AmazonS3.class); - ObjectListing objectListing = mock(ObjectListing.class); - S3Object object = mock(S3Object.class); - when(object.getObjectContent()).thenReturn(mock(S3ObjectInputStream.class)); - ObjectMetadata objectMetadata = mock(ObjectMetadata.class); - when(objectMetadata.getContentType()).thenReturn("image/png"); - when(objectMetadata.getContentLength()).thenReturn(90l); - when(object.getObjectMetadata()).thenReturn(objectMetadata); - when(object.getKey()).thenReturn("1_test.png"); - when(client.listObjects(eq(BUCKET_NAME), eq("1_test.png"))).thenReturn(objectListing); - when(client.getObject(eq(BUCKET_NAME), eq("1_test.png"))).thenReturn(object); - - S3ObjectSummary objectToDelete = mock(S3ObjectSummary.class); - when(objectToDelete.getKey()).thenReturn("1_test.png"); - List<S3ObjectSummary> objectSummaries = Collections.singletonList(objectToDelete); - when(objectListing.getObjectSummaries()).thenReturn(objectSummaries); + S3Client client = spy(S3Client.class); + ListObjectsResponse objectListing = mock(ListObjectsResponse.class); + doReturn(objectListing).when(client) + .listObjects(eq(ListObjectsRequest.builder().bucket(BUCKET_NAME).prefix("1_test.png").build())); + ResponseInputStream<GetObjectResponse> objectStream = mock(ResponseInputStream.class); + GetObjectResponse getObjectResponse = mock(GetObjectResponse.class); + when(getObjectResponse.contentType()).thenReturn("image/png"); + when(getObjectResponse.contentLength()).thenReturn(90l); + when(objectStream.response()).thenReturn(getObjectResponse); + doReturn(objectStream).when(client).getObject(any(GetObjectRequest.class)); + doReturn(DeleteObjectResponse.builder().build()).when(client).deleteObject(any(DeleteObjectRequest.class)); + + S3Object objectToDelete = mock(S3Object.class); + when(objectToDelete.key()).thenReturn("1_test.png"); + List<S3Object> objectSummaries = Collections.singletonList(objectToDelete); + when(objectListing.contents()).thenReturn(objectSummaries); + S3RasterStorage s3RasterStorage = new S3RasterStorage(client, BUCKET_NAME); StorageEvent storageEvent = mock(StorageEvent.class); s3RasterStorage.deleteRasterFile(1, "test.png", storageEvent); - verify(client).deleteObject(BUCKET_NAME, "1_test.png"); + verify(client).deleteObject(DeleteObjectRequest.builder().bucket(BUCKET_NAME).key("1_test.png").build()); ArgumentCaptor<de.latlon.xplan.commons.s3.S3Object> argument = ArgumentCaptor .forClass(de.latlon.xplan.commons.s3.S3Object.class); verify(storageEvent).addDeletedKey(argument.capture()); @@ -98,12 +126,23 @@ class S3RasterStorageTest { when(referenceEntry.getContentLength()).thenReturn(90l); when(referenceEntry.getContentType()).thenReturn("image/png"); when(mock.getEntry("test.png")).thenReturn(referenceEntry); + when(mock.retrieveInputStreamFor("test.png")).thenReturn(new ByteArrayInputStream("test.png".getBytes())); ArchiveEntry georefEntry = mock(ArchiveEntry.class); when(georefEntry.getContentLength()).thenReturn(10l); when(georefEntry.getContentType()).thenReturn("application/xml"); when(mock.getEntry("test.png.aux.xml")).thenReturn(georefEntry); + when(mock.retrieveInputStreamFor("test.png.aux.xml")) + .thenReturn(new ByteArrayInputStream("test.png.aux.xml".getBytes())); return mock; } + private static S3Client createS3ClientSpy() { + S3Client client = spy(S3Client.class); + doReturn(HeadBucketResponse.builder().build()).when(client).headBucket(any(HeadBucketRequest.class)); + doReturn(PutObjectResponse.builder().build()).when(client) + .putObject(any(PutObjectRequest.class), any(RequestBody.class)); + return client; + } + } diff --git a/xplan-core/xplan-core-manager/src/test/java/de/latlon/xplan/manager/wmsconfig/raster/storage/s3/S3RasterStorageTestManual.java b/xplan-core/xplan-core-manager/src/test/java/de/latlon/xplan/manager/wmsconfig/raster/storage/s3/S3RasterStorageTestManual.java index e8fb6b114c20a822e3f9053613e40185ee7e4c22..9913c8322502af1b7b1f3dac12cfa0834503ee38 100644 --- a/xplan-core/xplan-core-manager/src/test/java/de/latlon/xplan/manager/wmsconfig/raster/storage/s3/S3RasterStorageTestManual.java +++ b/xplan-core/xplan-core-manager/src/test/java/de/latlon/xplan/manager/wmsconfig/raster/storage/s3/S3RasterStorageTestManual.java @@ -42,7 +42,7 @@ import de.latlon.xplan.commons.archive.XPlanArchiveCreator; import de.latlon.xplan.commons.s3.S3Object; import de.latlon.xplan.commons.s3.StorageException; import de.latlon.xplan.manager.storage.StorageEvent; -import de.latlon.xplan.manager.storage.s3.config.AmazonS3TestContext; +import de.latlon.xplan.manager.storage.s3.config.TestS3Context; import de.latlon.xplan.manager.wmsconfig.raster.storage.s3.config.AmazonS3RasterStorageContext; /** @@ -56,7 +56,7 @@ import de.latlon.xplan.manager.wmsconfig.raster.storage.s3.config.AmazonS3Raster * @author <a href="mailto:goltz@lat-lon.de">Lyn Goltz </a> * @author <a href="mailto:friebe@lat-lon.de">Torsten Friebe</a> */ -@ContextConfiguration(classes = { AmazonS3RasterStorageContext.class, AmazonS3TestContext.class }) +@ContextConfiguration(classes = { AmazonS3RasterStorageContext.class, TestS3Context.class }) @ActiveProfiles({ "mock" }) @TestPropertySource("classpath:s3Mock.properties") @ExtendWith(SpringExtension.class) diff --git a/xplan-core/xplan-core-manager/src/test/resources/s3Mock.properties b/xplan-core/xplan-core-manager/src/test/resources/s3Mock.properties index 22040175b133db2307d5ee576668f43b1bbbe4dd..e1c35a7df9c482b929e44a1b70db54e52e59d04d 100644 --- a/xplan-core/xplan-core-manager/src/test/resources/s3Mock.properties +++ b/xplan-core/xplan-core-manager/src/test/resources/s3Mock.properties @@ -18,8 +18,8 @@ # along with this program. If not, see <http://www.gnu.org/licenses/>. # #L% ### -xplanbox.s3.accessKeyId= -xplanbox.s3.secretKey= -xplanbox.s3.bucketName=latlonxpb +xplanbox.s3.accessKeyId=test +xplanbox.s3.secretKey=test +xplanbox.s3.bucketName=latlonxpbtest xplanbox.s3.region=eu-central-1 xplanbox.s3.endpoint.url=http://localhost diff --git a/xplan-docker/xplan-docker-volume-init/setupVolumes.sh b/xplan-docker/xplan-docker-volume-init/setupVolumes.sh index ad5e4587a117a9c608771edfb5b793c826ff866d..2f93825aa3f0fb6a217c8c276ce01f49f449a82f 100755 --- a/xplan-docker/xplan-docker-volume-init/setupVolumes.sh +++ b/xplan-docker/xplan-docker-volume-init/setupVolumes.sh @@ -130,10 +130,14 @@ find xplan-workspaces/xplan-manager-workspace/datasources/feature -iname *.xml - find xplan-workspaces/xplan-services-wfs-workspace/datasources/feature -iname *.xml -exec sed -i 's|<StorageCRS srid="25832"|<StorageCRS srid="'$XPLAN_SERVICES_DEFAULT_CRS_SRID'"|g' {} \; find xplan-workspaces/xplan-services-wms-workspace/datasources/feature -iname *.xml -exec sed -i 's|<StorageCRS srid="25832"|<StorageCRS srid="'$XPLAN_SERVICES_DEFAULT_CRS_SRID'"|g' {} \; find xplan-workspaces/xplan-services-wfs-syn-workspace/datasources/feature -iname *.xml -exec sed -i 's|<StorageCRS srid="25832"|<StorageCRS srid="'$XPLAN_SERVICES_DEFAULT_CRS_SRID'"|g' {} \; +find xplan-validator-workspaces/xplan-validator-workspace/datasources/feature -iname *.xml -exec sed -i 's|<StorageCRS srid="25832"|<StorageCRS srid="'$XPLAN_SERVICES_DEFAULT_CRS_SRID'"|g' {} \; +find xplan-validator-workspaces/xplan-webservices-validator-wms-workspace/datasources/feature -iname *.xml -exec sed -i 's|<StorageCRS srid="25832"|<StorageCRS srid="'$XPLAN_SERVICES_DEFAULT_CRS_SRID'"|g' {} \; find xplan-workspaces/xplan-manager-workspace/datasources/feature -iname *.xml -exec sed -i 's|EPSG:25832</StorageCRS>|'$XPLAN_SERVICES_DEFAULT_CRS'</StorageCRS>|g' {} \; find xplan-workspaces/xplan-services-wfs-workspace/datasources/feature -iname *.xml -exec sed -i 's|EPSG:25832</StorageCRS>|'$XPLAN_SERVICES_DEFAULT_CRS'</StorageCRS>|g' {} \; find xplan-workspaces/xplan-services-wms-workspace/datasources/feature -iname *.xml -exec sed -i 's|EPSG:25832</StorageCRS>|'$XPLAN_SERVICES_DEFAULT_CRS'</StorageCRS>|g' {} \; find xplan-workspaces/xplan-services-wfs-syn-workspace/datasources/feature -iname *.xml -exec sed -i 's|EPSG:25832</StorageCRS>|'$XPLAN_SERVICES_DEFAULT_CRS'</StorageCRS>|g' {} \; +find xplan-validator-workspaces/xplan-validator-workspace/datasources/feature -iname *.xml -exec sed -i 's|EPSG:25832</StorageCRS>|'$XPLAN_SERVICES_DEFAULT_CRS'</StorageCRS>|g' {} \; +find xplan-validator-workspaces/xplan-webservices-validator-wms-workspace/datasources/feature -iname *.xml -exec sed -i 's|EPSG:25832</StorageCRS>|'$XPLAN_SERVICES_DEFAULT_CRS'</StorageCRS>|g' {} \; echo "[$(date -Iseconds)] Configure XPlanWMS CRS" find xplan-workspaces/xplan-services-wms-workspace/themes -iname *.xml -exec sed -i 's/<s:CRS>EPSG:25832 EPSG:25833 EPSG:31466 EPSG:31467 EPSG:31468 EPSG:31469 EPSG:4258 EPSG:4326 CRS:84 EPSG:4839<\/s:CRS>/<s:CRS>'"$XPLAN_SERVICES_DEFAULT_CRS $( echo ${XPLAN_SERVICES_QUERY_CRS_ARR[@]} )"'<\/s:CRS>/g' {} \; find xplan-workspaces/xplan-services-wms-workspace/themes -iname *raster.xml -exec sed -i 's|<s:CRS>EPSG:25832</s:CRS>|<s:CRS>'$XPLAN_SERVICES_DEFAULT_CRS'</s:CRS>|g' {} \; @@ -184,7 +188,7 @@ find xplan-workspaces/xplan-services-wfs-syn-workspace/services -iname xplansynw # Rastertype echo "[$(date -Iseconds)] Configure rastertype mapserver" -sed -i 's|http://localhost:8080/mapserver?|'$XPLAN_MAPSERVER_URL_INTERNAL'/mapserver?map=/etc/mapserver/internal.map\&|g' xplan-workspaces/xplan-services-wms-workspace/datasources/remoteows/mapserver.xml +sed -i 's|http://localhost:8080/xplan-mapserver?|'$XPLAN_MAPSERVER_URL_INTERNAL'/xplan-mapserver?map=/etc/mapserver/internal.map\&|g' xplan-workspaces/xplan-services-wms-workspace/datasources/remoteows/mapserver.xml #copy example external codelist XPLAN_INIT_EXAMPLE_CODELIST="${XPLAN_INIT_EXAMPLE_CODELIST:-disabled}" diff --git a/xplan-dokumente/xplan-dokumente-api/Dockerfile b/xplan-dokumente/xplan-dokumente-api/Dockerfile index c208683ded9c831ebe998eaebe0a5c5191ea4071..b5e7237e0a6beea3114b419f51ddd6cac063f4f2 100644 --- a/xplan-dokumente/xplan-dokumente-api/Dockerfile +++ b/xplan-dokumente/xplan-dokumente-api/Dockerfile @@ -32,7 +32,6 @@ COPY --from=builder $JMX_EXPORTER_DIR $JMX_EXPORTER_DIR # set environment variables ENV JAVA_ADDITIONAL_ARG_APP="-Duser.timezone=Europe/Berlin" \ JAVA_ADDITIONAL_ARG_JAVA17_EXPORTS="--add-exports=java.desktop/com.sun.imageio.spi=ALL-UNNAMED" \ - JAVA_ADDITIONAL_ARG_DISABLE_AWS_DEPRECATION="-Daws.java.v1.disableDeprecationAnnouncement=true" \ JAVA_ADDITIONAL_ARG_JMX_EXPORTER='-javaagent:$JMX_EXPORTER_DIR/jmx_prometheus_javaagent-1.0.1.jar=12345:$JMX_EXPORTER_DIR/jmx-exporter.config.yaml' \ XPLANBOX_CONFIG="/xplanbox/xplan-dokumente-config/" diff --git a/xplan-dokumente/xplan-dokumente-api/pom.xml b/xplan-dokumente/xplan-dokumente-api/pom.xml index 8a4fdff7a8b8c909194573fcce0d833b638584db..9d2ebf99c21962eefc99a61e0899fddf0378ce8e 100755 --- a/xplan-dokumente/xplan-dokumente-api/pom.xml +++ b/xplan-dokumente/xplan-dokumente-api/pom.xml @@ -287,7 +287,7 @@ <id>docker</id> <properties> <docker-image.skip>false</docker-image.skip> - <docker-contextTarFile.expectedSizeInMat10pct>112</docker-contextTarFile.expectedSizeInMat10pct> + <docker-contextTarFile.expectedSizeInMat10pct>126</docker-contextTarFile.expectedSizeInMat10pct> </properties> <dependencies> <dependency> <!-- faked maven dependency to be after base docker image in the reactor build --> diff --git a/xplan-dokumente/xplan-dokumente-api/src/main/java/de/latlon/xplanbox/api/dokumente/config/S3DocumentContext.java b/xplan-dokumente/xplan-dokumente-api/src/main/java/de/latlon/xplanbox/api/dokumente/config/S3DocumentContext.java index c3e0e9d1cb7bc3d2ac7f9014a91c77f6692cfb48..3c463f0ab40ab76e15ea375da6dfb3d2a9d6a25f 100644 --- a/xplan-dokumente/xplan-dokumente-api/src/main/java/de/latlon/xplanbox/api/dokumente/config/S3DocumentContext.java +++ b/xplan-dokumente/xplan-dokumente-api/src/main/java/de/latlon/xplanbox/api/dokumente/config/S3DocumentContext.java @@ -22,7 +22,6 @@ package de.latlon.xplanbox.api.dokumente.config; import static org.slf4j.LoggerFactory.getLogger; -import com.amazonaws.services.s3.AmazonS3; import de.latlon.xplan.commons.s3.S3Storage; import de.latlon.xplan.commons.s3.config.AmazonS3ReadOnlyContext; import org.slf4j.Logger; @@ -30,6 +29,7 @@ import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Import; +import software.amazon.awssdk.services.s3.S3Client; /** * @author <a href="mailto:goltz@lat-lon.de">Lyn Goltz </a> @@ -42,7 +42,7 @@ public class S3DocumentContext { private static final Logger LOG = getLogger(S3DocumentContext.class); @Bean - public S3Storage documentStorage(AmazonS3 s3Client, + public S3Storage documentStorage(S3Client s3Client, @Value("${xplanbox.s3.bucketName:#{environment.XPLAN_S3_BUCKET_ATTACHMENTS}}") String bucketName) { LOG.info("Instantiate S3Storage to manage documents"); return new S3Storage(s3Client, bucketName); diff --git a/xplan-dokumente/xplan-dokumente-api/src/main/java/de/latlon/xplanbox/api/dokumente/service/s3/S3DocumentService.java b/xplan-dokumente/xplan-dokumente-api/src/main/java/de/latlon/xplanbox/api/dokumente/service/s3/S3DocumentService.java index 5a6d4c04a0df8f538100de274078afc3905de836..4851028a766bb3be2a22b0f751b8a0b89a018b23 100644 --- a/xplan-dokumente/xplan-dokumente-api/src/main/java/de/latlon/xplanbox/api/dokumente/service/s3/S3DocumentService.java +++ b/xplan-dokumente/xplan-dokumente-api/src/main/java/de/latlon/xplanbox/api/dokumente/service/s3/S3DocumentService.java @@ -26,11 +26,6 @@ import java.io.ByteArrayInputStream; import java.util.List; import java.util.stream.Collectors; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Service; - -import com.amazonaws.services.s3.model.S3ObjectSummary; - import de.latlon.xplan.commons.s3.S3Metadata; import de.latlon.xplan.commons.s3.S3Object; import de.latlon.xplan.commons.s3.S3Storage; @@ -41,6 +36,8 @@ import de.latlon.xplanbox.api.dokumente.service.DocumentHeaderWithStream; import de.latlon.xplanbox.api.dokumente.service.DocumentService; import de.latlon.xplanbox.api.dokumente.v1.model.Document; import jakarta.ws.rs.core.StreamingOutput; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; /** * Implementation of a {@link DocumentService} retrieving the documents from S3. @@ -57,9 +54,9 @@ public class S3DocumentService implements DocumentService { @Override public List<Document> listDocuments(int planId) { String prefix = planId + "_"; - List<S3ObjectSummary> s3ObjectSummaries = documentStorage.listObjects(prefix); + List<software.amazon.awssdk.services.s3.model.S3Object> s3ObjectSummaries = documentStorage.listObjects(prefix); return s3ObjectSummaries.stream() - .map(s3ObjectSummary -> new Document().fileName(s3ObjectSummary.getKey().replaceFirst(prefix, ""))) + .map(s3ObjectSummary -> new Document().fileName(s3ObjectSummary.key().replaceFirst(prefix, ""))) .collect(Collectors.toList()); } diff --git a/xplan-dokumente/xplan-dokumente-api/src/test/java/de/latlon/xplanbox/api/dokumente/config/TestS3Context.java b/xplan-dokumente/xplan-dokumente-api/src/test/java/de/latlon/xplanbox/api/dokumente/config/TestS3Context.java index 59ed360dbb19fd11be63770d035a83c27b5019eb..6ead8f6560e967146f715f939b38dd01d42dfc25 100644 --- a/xplan-dokumente/xplan-dokumente-api/src/test/java/de/latlon/xplanbox/api/dokumente/config/TestS3Context.java +++ b/xplan-dokumente/xplan-dokumente-api/src/test/java/de/latlon/xplanbox/api/dokumente/config/TestS3Context.java @@ -8,32 +8,36 @@ * it under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. - * + * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * + * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. * #L% */ package de.latlon.xplanbox.api.dokumente.config; -import com.amazonaws.auth.AWSCredentials; -import com.amazonaws.auth.AWSStaticCredentialsProvider; -import com.amazonaws.auth.AnonymousAWSCredentials; -import com.amazonaws.auth.BasicAWSCredentials; -import com.amazonaws.client.builder.AwsClientBuilder; -import com.amazonaws.services.s3.AmazonS3; -import com.amazonaws.services.s3.AmazonS3ClientBuilder; +import static software.amazon.awssdk.regions.Region.EU_CENTRAL_1; + +import java.net.URI; +import java.net.URISyntaxException; + import io.findify.s3mock.S3Mock; import jakarta.annotation.PreDestroy; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Primary; +import org.springframework.context.annotation.Profile; import org.springframework.test.util.TestSocketUtils; +import software.amazon.awssdk.auth.credentials.AwsBasicCredentials; +import software.amazon.awssdk.auth.credentials.StaticCredentialsProvider; +import software.amazon.awssdk.services.s3.S3Client; +import software.amazon.awssdk.services.s3.S3Configuration; +import software.amazon.awssdk.services.s3.model.CreateBucketRequest; /** * @author <a href="mailto:goltz@lat-lon.de">Lyn Goltz </a> @@ -44,11 +48,12 @@ public class TestS3Context { private final int port = TestSocketUtils.findAvailableTcpPort(); - private AmazonS3 s3TestClient; + private S3Client s3TestClient; private S3Mock s3Mock; @Bean + @Profile("mock") public S3Mock s3Mock() { this.s3Mock = new S3Mock.Builder().withPort(port).withInMemoryBackend().build(); s3Mock.start(); @@ -57,28 +62,25 @@ public class TestS3Context { @Bean @Primary - public AmazonS3 s3Client(S3Mock s3Mock, @Value("${xplanbox.s3.bucketName}") String bucketName) { - AwsClientBuilder.EndpointConfiguration endpoint = new AwsClientBuilder.EndpointConfiguration( - "http://localhost:" + port, "eu-central-1"); - AmazonS3 client = AmazonS3ClientBuilder.standard() - .withPathStyleAccessEnabled(true) - .withEndpointConfiguration(endpoint) - .withCredentials(new AWSStaticCredentialsProvider(new AnonymousAWSCredentials())) + @Profile("mock") + public S3Client s3Client(S3Mock s3Mock, @Value("${xplanbox.s3.bucketName}") String bucketName) + throws URISyntaxException { + URI endpoint = new URI("http://localhost:" + port); + S3Client client = S3Client.builder() + .serviceConfiguration(S3Configuration.builder().pathStyleAccessEnabled(true).build()) + .endpointOverride(endpoint) + .credentialsProvider( + StaticCredentialsProvider.create(AwsBasicCredentials.create("accessKeyId", "secretKey"))) + .region(EU_CENTRAL_1) .build(); - client.createBucket(bucketName); + client.createBucket(CreateBucketRequest.builder().bucket(bucketName).build()); s3TestClient = client; return client; } - @Bean - @Primary - public AWSCredentials credentials() { - return new BasicAWSCredentials("accessKeyId", "secretKey"); - } - @PreDestroy public void shutdown() { - s3TestClient.shutdown(); + s3TestClient.close(); if (s3Mock != null) { s3Mock.stop(); } diff --git a/xplan-dokumente/xplan-dokumente-api/src/test/java/de/latlon/xplanbox/api/dokumente/handler/DocumentHandlerTest.java b/xplan-dokumente/xplan-dokumente-api/src/test/java/de/latlon/xplanbox/api/dokumente/handler/DocumentHandlerTest.java index 5f8ae0141e20678eff404fd9d77a0cf2df7c9d3e..8eae5c891d778d37bc2899d51a8b78d810ac75bf 100644 --- a/xplan-dokumente/xplan-dokumente-api/src/test/java/de/latlon/xplanbox/api/dokumente/handler/DocumentHandlerTest.java +++ b/xplan-dokumente/xplan-dokumente-api/src/test/java/de/latlon/xplanbox/api/dokumente/handler/DocumentHandlerTest.java @@ -8,12 +8,12 @@ * it under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. - * + * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * + * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. * #L% @@ -39,13 +39,6 @@ import java.util.List; import java.util.Objects; import java.util.zip.GZIPOutputStream; -import com.amazonaws.auth.AWSCredentials; -import com.amazonaws.auth.AWSStaticCredentialsProvider; -import com.amazonaws.auth.AnonymousAWSCredentials; -import com.amazonaws.auth.BasicAWSCredentials; -import com.amazonaws.client.builder.AwsClientBuilder; -import com.amazonaws.services.s3.AmazonS3; -import com.amazonaws.services.s3.AmazonS3ClientBuilder; import de.latlon.xplan.commons.s3.S3Storage; import de.latlon.xplan.core.manager.db.model.Artefact; import de.latlon.xplan.core.manager.db.model.ArtefactId; @@ -57,23 +50,19 @@ import de.latlon.xplanbox.api.commons.exception.InvalidPlanId; import de.latlon.xplanbox.api.commons.exception.InvalidPlanIdSyntax; import de.latlon.xplanbox.api.dokumente.config.ApplicationContext; import de.latlon.xplanbox.api.dokumente.config.HsqlJpaContext; +import de.latlon.xplanbox.api.dokumente.config.TestS3Context; import de.latlon.xplanbox.api.dokumente.exception.InvalidDocument; import de.latlon.xplanbox.api.dokumente.service.DocumentHeader; import de.latlon.xplanbox.api.dokumente.service.DocumentHeaderWithStream; import de.latlon.xplanbox.api.dokumente.v1.model.Document; -import io.findify.s3mock.S3Mock; -import jakarta.annotation.PreDestroy; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Primary; import org.springframework.test.annotation.Commit; +import org.springframework.test.context.ActiveProfiles; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.TestPropertySource; import org.springframework.test.context.junit.jupiter.SpringExtension; -import org.springframework.test.util.TestSocketUtils; import org.springframework.transaction.annotation.Transactional; /** @@ -81,59 +70,12 @@ import org.springframework.transaction.annotation.Transactional; * @since 7.0 */ @ExtendWith(SpringExtension.class) -@ContextConfiguration( - classes = { ApplicationContext.class, HsqlJpaContext.class, DocumentHandlerTest.TestConfig.class }) +@ContextConfiguration(classes = { ApplicationContext.class, HsqlJpaContext.class, TestS3Context.class }) @Transactional -@TestPropertySource(properties = "xplanbox.s3.bucketName=my-test-bucket") +@TestPropertySource("classpath:s3Mock.properties") +@ActiveProfiles({ "mock", "test" }) class DocumentHandlerTest { - static class TestConfig { - - private final int port = TestSocketUtils.findAvailableTcpPort(); - - private AmazonS3 s3TestClient; - - @Autowired - private S3Mock s3Mock; - - @Bean - public S3Mock s3Mock() { - S3Mock s3Mock = new S3Mock.Builder().withPort(port).withInMemoryBackend().build(); - s3Mock.start(); - return s3Mock; - } - - @Bean - @Primary - public AmazonS3 s3Client(S3Mock s3Mock, @Value("${xplanbox.s3.bucketName}") String bucketName) { - AwsClientBuilder.EndpointConfiguration endpoint = new AwsClientBuilder.EndpointConfiguration( - "http://localhost:" + port, "eu-central-1"); - AmazonS3 client = AmazonS3ClientBuilder.standard() - .withPathStyleAccessEnabled(true) - .withEndpointConfiguration(endpoint) - .withCredentials(new AWSStaticCredentialsProvider(new AnonymousAWSCredentials())) - .build(); - client.createBucket(bucketName); - s3TestClient = client; - return client; - } - - @Bean - @Primary - public AWSCredentials credentials() { - return new BasicAWSCredentials("accessKeyId", "secretKey"); - } - - @PreDestroy - public void shutdown() { - s3TestClient.shutdown(); - if (s3Mock != null) { - s3Mock.stop(); - } - } - - } - @Autowired private DocumentHandler documentHandler; diff --git a/xplan-dokumente/xplan-dokumente-api/src/test/java/de/latlon/xplanbox/api/dokumente/v1/DokumenteApiJerseyTest.java b/xplan-dokumente/xplan-dokumente-api/src/test/java/de/latlon/xplanbox/api/dokumente/v1/DokumenteApiJerseyTest.java index 7656b1028f26e746185805142eb8155861880849..b94e813ef0d6c1fb72dee157a8ee132b6ad3c1e6 100644 --- a/xplan-dokumente/xplan-dokumente-api/src/test/java/de/latlon/xplanbox/api/dokumente/v1/DokumenteApiJerseyTest.java +++ b/xplan-dokumente/xplan-dokumente-api/src/test/java/de/latlon/xplanbox/api/dokumente/v1/DokumenteApiJerseyTest.java @@ -52,6 +52,7 @@ public abstract class DokumenteApiJerseyTest<T> extends JerseyTest { Map<String, Object> map = Collections.singletonMap("xplanbox.s3.bucketName", "test-bucket"); PropertySource<?> propertySource = new MapPropertySource("dokumente-api", map); env.getPropertySources().addLast(propertySource); + env.setActiveProfiles("mock", "test"); context.setEnvironment(env); context.register(ApplicationContext.class, TestContext.class); context.refresh(); diff --git a/xplan-dokumente/xplan-dokumente-api/src/test/resources/s3Mock.properties b/xplan-dokumente/xplan-dokumente-api/src/test/resources/s3Mock.properties new file mode 100644 index 0000000000000000000000000000000000000000..32c458100eddc1d6866f96b85037b729ffa4c7c9 --- /dev/null +++ b/xplan-dokumente/xplan-dokumente-api/src/test/resources/s3Mock.properties @@ -0,0 +1,25 @@ +### +# #%L +# xplan-manager-core - XPlan Manager Core Komponente +# %% +# Copyright (C) 2008 - 2025 Freie und Hansestadt Hamburg, developed by lat/lon gesellschaft für raumbezogene Informationssysteme mbH +# %% +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# #L% +### +xplanbox.s3.accessKeyId= +xplanbox.s3.secretKey= +xplanbox.s3.bucketName=latlonxpbtest +xplanbox.s3.region=eu-central-1 +xplanbox.s3.endpoint.url=http://localhost diff --git a/xplan-manager/xplan-manager-api/Dockerfile b/xplan-manager/xplan-manager-api/Dockerfile index 1214b0cbd9d0ca07a8244974e425b3d7619c7bfd..1e7c0d14c5a920efa43304c8c7d174c3354f47d9 100644 --- a/xplan-manager/xplan-manager-api/Dockerfile +++ b/xplan-manager/xplan-manager-api/Dockerfile @@ -32,7 +32,6 @@ COPY --from=builder $JMX_EXPORTER_DIR $JMX_EXPORTER_DIR ENV DEEGREE_WORKSPACE_ROOT=/xplanbox/deegree \ JAVA_ADDITIONAL_ARG_APP="-Djavax.xml.transform.TransformerFactory=net.sf.saxon.TransformerFactoryImpl -Djts.overlay=ng -Duser.timezone=Europe/Berlin" \ JAVA_ADDITIONAL_ARG_JAVA17_EXPORTS="--add-exports=java.desktop/com.sun.imageio.spi=ALL-UNNAMED" \ - JAVA_ADDITIONAL_ARG_DISABLE_AWS_DEPRECATION="-Daws.java.v1.disableDeprecationAnnouncement=true" \ JAVA_ADDITIONAL_ARG_JMX_EXPORTER='-javaagent:$JMX_EXPORTER_DIR/jmx_prometheus_javaagent-1.0.1.jar=12345:$JMX_EXPORTER_DIR/jmx-exporter.config.yaml' \ XPLANBOX_CONFIG="/xplanbox/xplan-manager-config/" diff --git a/xplan-manager/xplan-manager-api/pom.xml b/xplan-manager/xplan-manager-api/pom.xml index 4b4dbbc6fc6b6736e0e79cd3ff1dea233655e049..31284b7186591ea0b40ab825d1b5648cacbea2ef 100644 --- a/xplan-manager/xplan-manager-api/pom.xml +++ b/xplan-manager/xplan-manager-api/pom.xml @@ -348,7 +348,7 @@ <id>docker</id> <properties> <docker-image.skip>false</docker-image.skip> - <docker-contextTarFile.expectedSizeInMat10pct>119</docker-contextTarFile.expectedSizeInMat10pct> + <docker-contextTarFile.expectedSizeInMat10pct>133</docker-contextTarFile.expectedSizeInMat10pct> </properties> <dependencies> <dependency> <!-- faked maven dependency to be after base docker image in the reactor build --> diff --git a/xplan-manager/xplan-manager-api/src/test/java/de/latlon/xplanbox/api/manager/ManagerApiJerseyTest.java b/xplan-manager/xplan-manager-api/src/test/java/de/latlon/xplanbox/api/manager/ManagerApiJerseyTest.java index 306943a35bf73e38b0f082ed2d1c17bbaf2452f6..8f6288fe88f954b6a08a58838e89e4f7ea74a9b8 100644 --- a/xplan-manager/xplan-manager-api/src/test/java/de/latlon/xplanbox/api/manager/ManagerApiJerseyTest.java +++ b/xplan-manager/xplan-manager-api/src/test/java/de/latlon/xplanbox/api/manager/ManagerApiJerseyTest.java @@ -50,7 +50,7 @@ public abstract class ManagerApiJerseyTest<T> extends JerseyTest { AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(); PropertySourcesPlaceholderConfigurer pph = new PropertySourcesPlaceholderConfigurer(); pph.setLocations(new ClassPathResource("/application.properties"), new ClassPathResource("/s3Mock.properties")); - context.getEnvironment().setActiveProfiles("test"); + context.getEnvironment().setActiveProfiles("mock", "test"); context.addBeanFactoryPostProcessor(pph); context.register(ApplicationContext.class, HsqlJpaContext.class, TestContext.class); context.refresh(); diff --git a/xplan-manager/xplan-manager-api/src/test/java/de/latlon/xplanbox/api/manager/config/TestS3Context.java b/xplan-manager/xplan-manager-api/src/test/java/de/latlon/xplanbox/api/manager/config/TestS3Context.java index bfb6cab5de14d9271a0780cce9406a937274c370..74785187f06866f1b6d38f3407b3b4b7ab54774b 100644 --- a/xplan-manager/xplan-manager-api/src/test/java/de/latlon/xplanbox/api/manager/config/TestS3Context.java +++ b/xplan-manager/xplan-manager-api/src/test/java/de/latlon/xplanbox/api/manager/config/TestS3Context.java @@ -8,34 +8,40 @@ * it under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. - * + * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * + * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. * #L% */ package de.latlon.xplanbox.api.manager.config; -import com.amazonaws.auth.AWSCredentials; -import com.amazonaws.auth.AWSStaticCredentialsProvider; -import com.amazonaws.auth.AnonymousAWSCredentials; -import com.amazonaws.auth.BasicAWSCredentials; -import com.amazonaws.client.builder.AwsClientBuilder; -import com.amazonaws.services.s3.AmazonS3; -import com.amazonaws.services.s3.AmazonS3ClientBuilder; +import static software.amazon.awssdk.regions.Region.EU_CENTRAL_1; + +import java.net.URI; +import java.net.URISyntaxException; + import io.findify.s3mock.S3Mock; import jakarta.annotation.PreDestroy; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Primary; +import org.springframework.context.annotation.Profile; import org.springframework.test.util.TestSocketUtils; +import software.amazon.awssdk.auth.credentials.AwsBasicCredentials; +import software.amazon.awssdk.auth.credentials.StaticCredentialsProvider; +import software.amazon.awssdk.services.s3.S3Client; +import software.amazon.awssdk.services.s3.S3Configuration; +import software.amazon.awssdk.services.s3.model.CreateBucketRequest; /** + * Spring Configuration to enable usage of mock objects for integration tests. + * * @author <a href="mailto:goltz@lat-lon.de">Lyn Goltz </a> * @since 8.0 */ @@ -44,11 +50,12 @@ public class TestS3Context { private final int port = TestSocketUtils.findAvailableTcpPort(); - private AmazonS3 s3TestClient; + private S3Client s3TestClient; private S3Mock s3Mock; @Bean + @Profile("mock") public S3Mock s3Mock() { this.s3Mock = new S3Mock.Builder().withPort(port).withInMemoryBackend().build(); s3Mock.start(); @@ -57,28 +64,25 @@ public class TestS3Context { @Bean @Primary - public AmazonS3 s3Client(S3Mock s3Mock, @Value("${xplanbox.s3.bucketName}") String bucketName) { - AwsClientBuilder.EndpointConfiguration endpoint = new AwsClientBuilder.EndpointConfiguration( - "http://localhost:" + port, "eu-central-1"); - AmazonS3 client = AmazonS3ClientBuilder.standard() - .withPathStyleAccessEnabled(true) - .withEndpointConfiguration(endpoint) - .withCredentials(new AWSStaticCredentialsProvider(new AnonymousAWSCredentials())) + @Profile("mock") + public S3Client s3Client(S3Mock s3Mock, @Value("${xplanbox.s3.bucketName}") String bucketName) + throws URISyntaxException { + URI endpoint = new URI("http://localhost:" + port); + S3Client client = S3Client.builder() + .serviceConfiguration(S3Configuration.builder().pathStyleAccessEnabled(true).build()) + .endpointOverride(endpoint) + .credentialsProvider( + StaticCredentialsProvider.create(AwsBasicCredentials.create("accessKeyId", "secretKey"))) + .region(EU_CENTRAL_1) .build(); - client.createBucket(bucketName); + client.createBucket(CreateBucketRequest.builder().bucket(bucketName).build()); s3TestClient = client; return client; } - @Bean - @Primary - public AWSCredentials credentials() { - return new BasicAWSCredentials("accessKeyId", "secretKey"); - } - @PreDestroy public void shutdown() { - s3TestClient.shutdown(); + s3TestClient.close(); if (s3Mock != null) { s3Mock.stop(); } diff --git a/xplan-manager/xplan-manager-api/src/test/java/de/latlon/xplanbox/api/manager/executor/PlanImporterTest.java b/xplan-manager/xplan-manager-api/src/test/java/de/latlon/xplanbox/api/manager/executor/PlanImporterTest.java index 7f906756c9f9eceae8cffc006ee458a4f06b5b88..e895ac9797ebd930c9eb644a4e1ce8cdc8d3f14b 100644 --- a/xplan-manager/xplan-manager-api/src/test/java/de/latlon/xplanbox/api/manager/executor/PlanImporterTest.java +++ b/xplan-manager/xplan-manager-api/src/test/java/de/latlon/xplanbox/api/manager/executor/PlanImporterTest.java @@ -67,7 +67,7 @@ import org.xmlunit.assertj.XmlAssert; @SpringBootTest(classes = { PlanImporter.class }) @ContextConfiguration(classes = { ApplicationContext.class, HsqlJpaContext.class, TestContext.class }) @TestPropertySource(value = "/s3Mock.properties", properties = "spring.main.allow-bean-definition-overriding=true") -@ActiveProfiles("test") +@ActiveProfiles({ "mock", "test" }) public class PlanImporterTest { @Autowired diff --git a/xplan-manager/xplan-manager-api/src/test/java/de/latlon/xplanbox/api/manager/handler/EditBasisdatenHandlerTest.java b/xplan-manager/xplan-manager-api/src/test/java/de/latlon/xplanbox/api/manager/handler/EditBasisdatenHandlerTest.java index 93da5890f69068eb267cbe367ccc7323b06a468d..21ab786b67bc318ef04716baf3b58214bd5f0f8c 100644 --- a/xplan-manager/xplan-manager-api/src/test/java/de/latlon/xplanbox/api/manager/handler/EditBasisdatenHandlerTest.java +++ b/xplan-manager/xplan-manager-api/src/test/java/de/latlon/xplanbox/api/manager/handler/EditBasisdatenHandlerTest.java @@ -41,7 +41,7 @@ import org.springframework.test.context.TestPropertySource; @SpringBootTest @ContextConfiguration(classes = { ApplicationContext.class, HsqlJpaContext.class, TestContext.class }) @TestPropertySource(value = "/s3Mock.properties", properties = "spring.main.allow-bean-definition-overriding=true") -@ActiveProfiles("test") +@ActiveProfiles({ "test", "mock" }) class EditBasisdatenHandlerTest { @Autowired diff --git a/xplan-manager/xplan-manager-api/src/test/java/de/latlon/xplanbox/api/manager/handler/PlanHandlerTest.java b/xplan-manager/xplan-manager-api/src/test/java/de/latlon/xplanbox/api/manager/handler/PlanHandlerTest.java index e07161290a2fc845328c490791e622a096e850e1..e5ba8a55a410a65a158207e9979aa019c796b086 100644 --- a/xplan-manager/xplan-manager-api/src/test/java/de/latlon/xplanbox/api/manager/handler/PlanHandlerTest.java +++ b/xplan-manager/xplan-manager-api/src/test/java/de/latlon/xplanbox/api/manager/handler/PlanHandlerTest.java @@ -47,7 +47,7 @@ import org.springframework.test.context.TestPropertySource; @SpringBootTest @ContextConfiguration(classes = { ApplicationContext.class, HsqlJpaContext.class, TestContext.class }) @TestPropertySource(value = "/s3Mock.properties", properties = "spring.main.allow-bean-definition-overriding=true") -@ActiveProfiles("test") +@ActiveProfiles({ "test", "mock" }) class PlanHandlerTest { @Autowired diff --git a/xplan-manager/xplan-manager-web/Dockerfile b/xplan-manager/xplan-manager-web/Dockerfile index 128e5b1c60c0f6556f14b4ceb6c8946f711ca98c..3fc34ba2bc2d74f83f9a85284db17fb321f165e2 100644 --- a/xplan-manager/xplan-manager-web/Dockerfile +++ b/xplan-manager/xplan-manager-web/Dockerfile @@ -23,7 +23,6 @@ LABEL "org.opencontainers.image.created"="$BUILD_DATE" \ ENV DEEGREE_WORKSPACE_ROOT=/xplanbox/deegree \ TOMCAT_ADDITIONAL_ARG_APP="-Djavax.xml.transform.TransformerFactory=net.sf.saxon.TransformerFactoryImpl -Djts.overlay=ng -Duser.timezone=Europe/Berlin" \ TOMCAT_ADDITIONAL_ARG_JAVA17_EXPORTS="--add-exports=java.desktop/com.sun.imageio.spi=ALL-UNNAMED" \ - TOMCAT_ADDITIONAL_ARG_DISABLE_AWS_DEPRECATION="-Daws.java.v1.disableDeprecationAnnouncement=true" \ XPLANBOX_CONFIG="/xplanbox/xplan-manager-config/" USER root diff --git a/xplan-manager/xplan-manager-web/pom.xml b/xplan-manager/xplan-manager-web/pom.xml index 30be0a16e5092d354a68889db38acb3793e0af62..1f61700a28b45836642f759bf9bff35b04a1ff4e 100644 --- a/xplan-manager/xplan-manager-web/pom.xml +++ b/xplan-manager/xplan-manager-web/pom.xml @@ -277,7 +277,7 @@ <id>docker</id> <properties> <docker-image.skip>false</docker-image.skip> - <docker-contextTarFile.expectedSizeInMat10pct>100</docker-contextTarFile.expectedSizeInMat10pct> + <docker-contextTarFile.expectedSizeInMat10pct>112</docker-contextTarFile.expectedSizeInMat10pct> </properties> <dependencies> <dependency> <!-- faked maven dependency to be after base docker image in the reactor build --> diff --git a/xplan-tests/xplan-tests-soapui/README.md b/xplan-tests/xplan-tests-soapui/README.md index 8b083486cf59a71e10d9416e2ef11652c1ade380..40277aef67439e633d020add6006329de5cdfd16 100644 --- a/xplan-tests/xplan-tests-soapui/README.md +++ b/xplan-tests/xplan-tests-soapui/README.md @@ -21,7 +21,6 @@ Bei Nutzung der Absicherung über ein Bearer Token muss zusätzlich die URL von ``` mvn clean test -Psystem-tests -DtestFileName=xplan-manager-api-soapui-project.xml \ -DbaseUrlManagerApi=https://xplanbox.lat-lon.de -Dusername=xplanbox -Dpassword='PWD' \ - -DbaseUrlServices=https://xplanbox.lat-lon.de \ -DjdbcUrl=jdbc:postgresql://localhost:5433/xplanbox?user=xplanbox&password=xplanbox ``` @@ -89,7 +88,7 @@ docker run --env ... xplanbox/xplan-tests-soapui - `XPLAN_DIENSTE_BASE_URL` - `XPLAN_DIENSTE_USERNAME` - `XPLAN_DIENSTE_PASSWORD` -- `XPLAN_DOKUMENTE_API_BASE_URL` - optional: XPlanDokumenteAPI Tests werden geskipped, wenn die Umgebungsvariable nicht gesetzt ist. +- `XPLAN_DOKUMENTE_API_BASE_URL` - optional: XPlanDokumenteAPI Tests werden übersprungen, wenn die Umgebungsvariable nicht gesetzt ist. - `XPLAN_DOKUMENTE_API_USERNAME` - `XPLAN_DOKUMENTE_API_PASSWORD` - `XPLAN_BASE_URL_INSPIRE_PLU` diff --git a/xplan-tests/xplan-tests-soapui/runAllSoapUiTests.sh b/xplan-tests/xplan-tests-soapui/runAllSoapUiTests.sh index 50bfb8ebb6d062683f03e98befaab7796b8a579b..79fe312972c14abf0e9c0114584dc58f1e14548e 100755 --- a/xplan-tests/xplan-tests-soapui/runAllSoapUiTests.sh +++ b/xplan-tests/xplan-tests-soapui/runAllSoapUiTests.sh @@ -66,7 +66,6 @@ mvn test -Psystem-tests -DtestFileName=xplan-manager-api-soapui-project.xml \ -DbaseUrlManagerApi=$XPLAN_MANAGER_API_BASE_URL \ -Dusername=$XPLAN_MANAGER_API_USERNAME -Dpassword=$XPLAN_MANAGER_API_PASSWORD \ -DjwtUrl=$XPLAN_JWT_URL -DjwtClientId=$XPLAN_JWT_CLIENTID \ - -DbaseUrlServices=$XPLAN_DIENSTE_BASE_URL \ -DjdbcUrl=$JDBC_URL mvn test -Psystem-tests -DtestFileName=xplan-validator-api-soapui-project.xml \ diff --git a/xplan-tests/xplan-tests-soapui/src/main/resources/xplan-dokumente-api-soapui-project.xml b/xplan-tests/xplan-tests-soapui/src/main/resources/xplan-dokumente-api-soapui-project.xml index 6c7d93439cb08e7cda7bcebc8aa3b55ab379bd26..176683e0fde8286d94558fef4455651e9bc537ca 100644 --- a/xplan-tests/xplan-tests-soapui/src/main/resources/xplan-dokumente-api-soapui-project.xml +++ b/xplan-tests/xplan-tests-soapui/src/main/resources/xplan-dokumente-api-soapui-project.xml @@ -17,7 +17,7 @@ You should have received a copy of the GNU Affero General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. #L%--> -<con:soapui-project id="c0330194-e671-4de1-89fb-fd5cd92eb5af" activeEnvironment="Default" name="xplan-dokumente-api" resourceRoot="" soapui-version="5.7.2" abortOnError="false" runType="SEQUENTIAL" xmlns:con="http://eviware.com/soapui/config"> +<con:soapui-project id="c0330194-e671-4de1-89fb-fd5cd92eb5af" activeEnvironment="Default" name="xplan-dokumente-api" resourceRoot="" soapui-version="5.8.0" abortOnError="false" runType="SEQUENTIAL" xmlns:con="http://eviware.com/soapui/config"> <con:description>For local execution use following property values: baseUrlManagerApi=http://localhost:8086/xplan-manager-api @@ -1789,4 +1789,4 @@ testRunner.testCase.testSuite.project.testSuiteList.each <con:oAuth2ProfileContainer/> <con:oAuth1ProfileContainer/> <con:sensitiveInformation/> -</con:soapui-project> +</con:soapui-project> \ No newline at end of file diff --git a/xplan-tests/xplan-tests-soapui/src/main/resources/xplan-loadtests-soapui-project.xml b/xplan-tests/xplan-tests-soapui/src/main/resources/xplan-loadtests-soapui-project.xml index 7b44ac4c614a53c2604eec852ac50bfc7f6fde1a..8795facaabea530d587786ac538aa2ce32410fe7 100644 --- a/xplan-tests/xplan-tests-soapui/src/main/resources/xplan-loadtests-soapui-project.xml +++ b/xplan-tests/xplan-tests-soapui/src/main/resources/xplan-loadtests-soapui-project.xml @@ -17,7 +17,7 @@ You should have received a copy of the GNU Affero General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. #L%--> -<con:soapui-project id="d87c2df2-24ee-4f03-93eb-b6af824e4cc9" activeEnvironment="Default" name="xplan-loadtests" resourceRoot="" soapui-version="5.7.2" abortOnError="false" runType="SEQUENTIAL" xmlns:con="http://eviware.com/soapui/config"> +<con:soapui-project id="d87c2df2-24ee-4f03-93eb-b6af824e4cc9" activeEnvironment="Default" name="xplan-loadtests" resourceRoot="" soapui-version="5.8.0" abortOnError="false" runType="SEQUENTIAL" xmlns:con="http://eviware.com/soapui/config"> <con:settings/> <con:testSuite id="701c0614-03fd-48eb-87a0-3bf0acbc151a" name="ImportAndPlanList"> <con:settings/> @@ -237,4 +237,4 @@ <con:oAuth2ProfileContainer/> <con:oAuth1ProfileContainer/> <con:sensitiveInformation/> -</con:soapui-project> +</con:soapui-project> \ No newline at end of file diff --git a/xplan-tests/xplan-tests-soapui/src/main/resources/xplan-manager-api-soapui-project.xml b/xplan-tests/xplan-tests-soapui/src/main/resources/xplan-manager-api-soapui-project.xml index 13bc028c376c5cfeec0cd882b74107438fa211d7..825545aa5dff8146e8e05464c7d569c79a8999a8 100644 --- a/xplan-tests/xplan-tests-soapui/src/main/resources/xplan-manager-api-soapui-project.xml +++ b/xplan-tests/xplan-tests-soapui/src/main/resources/xplan-manager-api-soapui-project.xml @@ -17,7 +17,7 @@ You should have received a copy of the GNU Affero General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. #L%--> -<con:soapui-project id="adcdfd3f-0f4e-4107-8d7e-086010676cb7" activeEnvironment="Default" name="xplan-manager-api" resourceRoot="" soapui-version="5.7.2" abortOnError="false" runType="SEQUENTIAL" xmlns:con="http://eviware.com/soapui/config"> +<con:soapui-project id="adcdfd3f-0f4e-4107-8d7e-086010676cb7" activeEnvironment="Default" name="xplan-manager-api" resourceRoot="" soapui-version="5.8.0" abortOnError="false" runType="SEQUENTIAL" xmlns:con="http://eviware.com/soapui/config"> <con:description>For local execution use following property values: baseUrlManagerApi=http://localhost:8086 diff --git a/xplan-tests/xplan-tests-soapui/src/main/resources/xplan-validator-api-soapui-project.xml b/xplan-tests/xplan-tests-soapui/src/main/resources/xplan-validator-api-soapui-project.xml index 0d191c63959535d0b7f508357453a3ea4b487b48..3170c81e299b075f8c53e9d59da3854a518a4790 100644 --- a/xplan-tests/xplan-tests-soapui/src/main/resources/xplan-validator-api-soapui-project.xml +++ b/xplan-tests/xplan-tests-soapui/src/main/resources/xplan-validator-api-soapui-project.xml @@ -17,7 +17,7 @@ You should have received a copy of the GNU Affero General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. #L%--> -<con:soapui-project id="45582ef9-4bae-43d8-9226-a378e02ff0b5" activeEnvironment="Default" name="xplan-validator-api" resourceRoot="" soapui-version="5.7.2" abortOnError="false" runType="SEQUENTIAL" xmlns:con="http://eviware.com/soapui/config"> +<con:soapui-project id="45582ef9-4bae-43d8-9226-a378e02ff0b5" activeEnvironment="Default" name="xplan-validator-api" resourceRoot="" soapui-version="5.8.0" abortOnError="false" runType="SEQUENTIAL" xmlns:con="http://eviware.com/soapui/config"> <con:description>Set this if Keycloak authentication shall be used locally: jwtUrl=http://localhost:8096/keycloak/realms/xplanbox/protocol/openid-connect/token diff --git a/xplan-tests/xplan-tests-soapui/src/main/resources/xplan-webservices-soapui-project.xml b/xplan-tests/xplan-tests-soapui/src/main/resources/xplan-webservices-soapui-project.xml index 08b620508b8dfc9a5659ee8aa2f0815b4bf31c58..b5a97056be1471b96b6ccc3596cd4dbaae0bb5db 100644 --- a/xplan-tests/xplan-tests-soapui/src/main/resources/xplan-webservices-soapui-project.xml +++ b/xplan-tests/xplan-tests-soapui/src/main/resources/xplan-webservices-soapui-project.xml @@ -17,7 +17,7 @@ You should have received a copy of the GNU Affero General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. #L%--> -<con:soapui-project id="4497dcb6-2c5f-4d87-bcee-3913ada70576" activeEnvironment="Default" name="xplan-webservices" resourceRoot="" soapui-version="5.7.2" abortOnError="false" runType="SEQUENTIAL" defaultScriptLanguage="Groovy" xmlns:con="http://eviware.com/soapui/config"> +<con:soapui-project id="4497dcb6-2c5f-4d87-bcee-3913ada70576" activeEnvironment="Default" name="xplan-webservices" resourceRoot="" soapui-version="5.8.0" abortOnError="false" runType="SEQUENTIAL" defaultScriptLanguage="Groovy" xmlns:con="http://eviware.com/soapui/config"> <con:description>For local execution use following property values: baseUrlServices=http://localhost:8083 @@ -16150,7 +16150,7 @@ exists(/wfs:WFS_Capabilities)</path> <con:settings> <con:setting id="com.eviware.soapui.impl.wsdl.WsdlRequest@request-headers"><xml-fragment/></con:setting> </con:settings> - <con:endpoint>${#Project#baseUrlMapServer}/mapserver.cgi</con:endpoint> + <con:endpoint>${#Project#baseUrlMapServer}/xplan-mapserver</con:endpoint> <con:request/> <con:assertion type="Valid HTTP Status Codes" id="2b2dc1c4-d8c4-4308-8c53-f98536940634" name="Valid HTTP Status Codes"> <con:configuration> @@ -16174,7 +16174,7 @@ exists(/wms:WMS_Capabilities)</path> declare namespace xlink='http://www.w3.org/1999/xlink'; /wms:WMS_Capabilities/wms:Capability/wms:Request/wms:GetCapabilities/wms:DCPType/wms:HTTP/wms:Get/wms:OnlineResource/@xlink:href</path> - <content>${#Project#baseUrlMapServer}/mapserver.cgi?</content> + <content>${#Project#baseUrlMapServer}/xplan-mapserver?</content> <allowWildcards>false</allowWildcards> <ignoreNamspaceDifferences>false</ignoreNamspaceDifferences> <ignoreComments>false</ignoreComments> @@ -16385,7 +16385,7 @@ declare namespace xlink='http://www.w3.org/1999/xlink'; <con:settings> <con:setting id="com.eviware.soapui.impl.wsdl.WsdlRequest@request-headers"><xml-fragment/></con:setting> </con:settings> - <con:endpoint>${#Project#baseUrlMapServer}/mapserver.cgi</con:endpoint> + <con:endpoint>${#Project#baseUrlMapServer}/xplan-mapserver</con:endpoint> <con:request/> <con:assertion type="Valid HTTP Status Codes" id="2b2dc1c4-d8c4-4308-8c53-f98536940634" name="Valid HTTP Status Codes"> <con:configuration> @@ -16406,7 +16406,7 @@ declare namespace xlink='http://www.w3.org/1999/xlink'; <path>declare namespace xlink='http://www.w3.org/1999/xlink'; /WMT_MS_Capabilities/Capability/Request/GetCapabilities/DCPType/HTTP/Get/OnlineResource/@xlink:href</path> - <content>${#Project#baseUrlMapServer}/mapserver.cgi?</content> + <content>${#Project#baseUrlMapServer}/xplan-mapserver?</content> <allowWildcards>false</allowWildcards> <ignoreNamspaceDifferences>false</ignoreNamspaceDifferences> <ignoreComments>false</ignoreComments> @@ -16456,7 +16456,7 @@ declare namespace xlink='http://www.w3.org/1999/xlink'; <con:settings> <con:setting id="com.eviware.soapui.impl.wsdl.WsdlRequest@request-headers"><xml-fragment/></con:setting> </con:settings> - <con:endpoint>${#Project#baseUrlMapServer}/mapserver.cgi</con:endpoint> + <con:endpoint>${#Project#baseUrlMapServer}/xplan-mapserver</con:endpoint> <con:request/> <con:assertion type="Valid HTTP Status Codes" id="2b2dc1c4-d8c4-4308-8c53-f98536940634" name="Valid HTTP Status Codes"> <con:configuration> diff --git a/xplan-validator/xplan-validator-api/Dockerfile b/xplan-validator/xplan-validator-api/Dockerfile index 94b56f1164489c5981c1ac406f7aa1633914bcca..88a07d554c552507f962b1d1100068d1fd7a293d 100644 --- a/xplan-validator/xplan-validator-api/Dockerfile +++ b/xplan-validator/xplan-validator-api/Dockerfile @@ -32,7 +32,6 @@ COPY --from=builder $JMX_EXPORTER_DIR $JMX_EXPORTER_DIR ENV DEEGREE_WORKSPACE_ROOT=/xplanbox/deegree \ JAVA_ADDITIONAL_ARG_APP="-Djavax.xml.transform.TransformerFactory=net.sf.saxon.TransformerFactoryImpl -Djts.overlay=ng -Duser.timezone=Europe/Berlin" \ JAVA_ADDITIONAL_ARG_JAVA17_EXPORTS="--add-exports=java.desktop/com.sun.imageio.spi=ALL-UNNAMED" \ - JAVA_ADDITIONAL_ARG_DISABLE_AWS_DEPRECATION="-Daws.java.v1.disableDeprecationAnnouncement=true" \ JAVA_ADDITIONAL_ARG_JMX_EXPORTER='-javaagent:$JMX_EXPORTER_DIR/jmx_prometheus_javaagent-1.0.1.jar=12345:$JMX_EXPORTER_DIR/jmx-exporter.config.yaml' \ XPLANBOX_CONFIG="/xplanbox/xplan-validator-config/" diff --git a/xplan-validator/xplan-validator-api/pom.xml b/xplan-validator/xplan-validator-api/pom.xml index 1e7ef97a9270db442a3d3b5c60248ff592689874..2df4838f654844b18613e4a4ab5de5e57c7fa5c3 100755 --- a/xplan-validator/xplan-validator-api/pom.xml +++ b/xplan-validator/xplan-validator-api/pom.xml @@ -261,8 +261,9 @@ <artifactId>xplan-core-validator-events</artifactId> </dependency> <dependency> - <groupId>com.amazonaws</groupId> - <artifactId>aws-java-sdk-s3</artifactId> + <groupId>software.amazon.awssdk</groupId> + <artifactId>s3</artifactId> + <version>2.30.10</version> </dependency> <dependency> <groupId>io.findify</groupId> @@ -275,7 +276,7 @@ <id>docker</id> <properties> <docker-image.skip>false</docker-image.skip> - <docker-contextTarFile.expectedSizeInMat10pct>91</docker-contextTarFile.expectedSizeInMat10pct> + <docker-contextTarFile.expectedSizeInMat10pct>101</docker-contextTarFile.expectedSizeInMat10pct> </properties> <dependencies> <dependency> <!-- to copy jmx exporter stuff from docker image --> diff --git a/xplan-validator/xplan-validator-api/src/test/java/de/latlon/xplanbox/api/validator/SpringBootAppTest.java b/xplan-validator/xplan-validator-api/src/test/java/de/latlon/xplanbox/api/validator/SpringBootAppTest.java index 4401ae5d93f45349c71a1dd3430faf5f858e7e75..147faf490e0a39e155b3def42e6504903080c92a 100644 --- a/xplan-validator/xplan-validator-api/src/test/java/de/latlon/xplanbox/api/validator/SpringBootAppTest.java +++ b/xplan-validator/xplan-validator-api/src/test/java/de/latlon/xplanbox/api/validator/SpringBootAppTest.java @@ -29,9 +29,8 @@ import org.springframework.test.context.TestPropertySource; @SpringBootTest @Import(TestContext.class) -@TestPropertySource(properties = { "spring.main.allow-bean-definition-overriding=true", - "xplanbox.s3.bucket.validation=test-bucket-validation" }) -@ActiveProfiles("test") +@ActiveProfiles({ "mock", "test" }) +@TestPropertySource(value = "/s3Mock.properties", properties = { "spring.main.allow-bean-definition-overriding=true" }) class SpringBootAppTest { @Test diff --git a/xplan-validator/xplan-validator-api/src/test/java/de/latlon/xplanbox/api/validator/ValidatorApiJerseyTest.java b/xplan-validator/xplan-validator-api/src/test/java/de/latlon/xplanbox/api/validator/ValidatorApiJerseyTest.java index f3be6da3a914162f1f6d4dabcfea3f9fa6f00677..87bdb7b1ca704a388928fa3ec9c76ae5546ead6e 100644 --- a/xplan-validator/xplan-validator-api/src/test/java/de/latlon/xplanbox/api/validator/ValidatorApiJerseyTest.java +++ b/xplan-validator/xplan-validator-api/src/test/java/de/latlon/xplanbox/api/validator/ValidatorApiJerseyTest.java @@ -57,6 +57,7 @@ public abstract class ValidatorApiJerseyTest extends JerseyTest { AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(); PropertySourcesPlaceholderConfigurer pph = new PropertySourcesPlaceholderConfigurer(); pph.setLocations(new ClassPathResource("/application.properties"), new ClassPathResource("/s3Mock.properties")); + context.getEnvironment().setActiveProfiles("test", "mock"); context.addBeanFactoryPostProcessor(pph); context.register(ApplicationContext.class, TestContext.class); context.refresh(); diff --git a/xplan-validator/xplan-validator-api/src/test/java/de/latlon/xplanbox/api/validator/config/TestS3Context.java b/xplan-validator/xplan-validator-api/src/test/java/de/latlon/xplanbox/api/validator/config/TestS3Context.java index a28cdbfa5d547a177bec9595aaa05e555af314cc..1d1c74552b0a9d5b3737f53a680b640ef9225de4 100644 --- a/xplan-validator/xplan-validator-api/src/test/java/de/latlon/xplanbox/api/validator/config/TestS3Context.java +++ b/xplan-validator/xplan-validator-api/src/test/java/de/latlon/xplanbox/api/validator/config/TestS3Context.java @@ -8,35 +8,40 @@ * it under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. - * + * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * + * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. * #L% */ package de.latlon.xplanbox.api.validator.config; -import com.amazonaws.auth.AWSCredentials; -import com.amazonaws.auth.AWSStaticCredentialsProvider; -import com.amazonaws.auth.AnonymousAWSCredentials; -import com.amazonaws.auth.BasicAWSCredentials; -import com.amazonaws.client.builder.AwsClientBuilder; -import com.amazonaws.services.s3.AmazonS3; -import com.amazonaws.services.s3.AmazonS3ClientBuilder; +import static software.amazon.awssdk.regions.Region.EU_CENTRAL_1; + +import java.net.URI; +import java.net.URISyntaxException; + import io.findify.s3mock.S3Mock; import jakarta.annotation.PreDestroy; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Primary; +import org.springframework.context.annotation.Profile; import org.springframework.test.util.TestSocketUtils; +import software.amazon.awssdk.auth.credentials.AwsBasicCredentials; +import software.amazon.awssdk.auth.credentials.StaticCredentialsProvider; +import software.amazon.awssdk.services.s3.S3Client; +import software.amazon.awssdk.services.s3.S3Configuration; +import software.amazon.awssdk.services.s3.model.CreateBucketRequest; /** + * Spring Configuration to enable usage of mock objects for integration tests. + * * @author <a href="mailto:goltz@lat-lon.de">Lyn Goltz </a> * @since 8.0 */ @@ -45,11 +50,12 @@ public class TestS3Context { private final int port = TestSocketUtils.findAvailableTcpPort(); - private AmazonS3 s3TestClient; + private S3Client s3TestClient; private S3Mock s3Mock; @Bean + @Profile("mock") public S3Mock s3Mock() { this.s3Mock = new S3Mock.Builder().withPort(port).withInMemoryBackend().build(); s3Mock.start(); @@ -58,28 +64,25 @@ public class TestS3Context { @Bean @Primary - public AmazonS3 s3Client(S3Mock s3Mock, @Value("${xplanbox.s3.bucket.validation}") String bucketName) { - AwsClientBuilder.EndpointConfiguration endpoint = new AwsClientBuilder.EndpointConfiguration( - "http://localhost:" + port, "eu-central-1"); - AmazonS3 client = AmazonS3ClientBuilder.standard() - .withPathStyleAccessEnabled(true) - .withEndpointConfiguration(endpoint) - .withCredentials(new AWSStaticCredentialsProvider(new AnonymousAWSCredentials())) + @Profile("mock") + public S3Client s3Client(S3Mock s3Mock, @Value("${xplanbox.s3.bucketName}") String bucketName) + throws URISyntaxException { + URI endpoint = new URI("http://localhost:" + port); + S3Client client = S3Client.builder() + .serviceConfiguration(S3Configuration.builder().pathStyleAccessEnabled(true).build()) + .endpointOverride(endpoint) + .credentialsProvider( + StaticCredentialsProvider.create(AwsBasicCredentials.create("accessKeyId", "secretKey"))) + .region(EU_CENTRAL_1) .build(); - client.createBucket(bucketName); + client.createBucket(CreateBucketRequest.builder().bucket(bucketName).build()); s3TestClient = client; return client; } - @Bean - @Primary - public AWSCredentials credentials() { - return new BasicAWSCredentials("accessKeyId", "secretKey"); - } - @PreDestroy public void shutdown() { - s3TestClient.shutdown(); + s3TestClient.close(); if (s3Mock != null) { s3Mock.stop(); } diff --git a/xplan-validator/xplan-validator-api/src/test/java/de/latlon/xplanbox/api/validator/handler/ConfigHandlerTest.java b/xplan-validator/xplan-validator-api/src/test/java/de/latlon/xplanbox/api/validator/handler/ConfigHandlerTest.java index 7ca8d0b89409cf03cb33fe59c711c4717e0a275a..a8ea146fbc4119e1f4ef43c1ee5b8db272c5ac97 100644 --- a/xplan-validator/xplan-validator-api/src/test/java/de/latlon/xplanbox/api/validator/handler/ConfigHandlerTest.java +++ b/xplan-validator/xplan-validator-api/src/test/java/de/latlon/xplanbox/api/validator/handler/ConfigHandlerTest.java @@ -40,8 +40,9 @@ import org.springframework.test.context.junit.jupiter.SpringExtension; */ @ExtendWith(SpringExtension.class) @ContextConfiguration(classes = { ApplicationContext.class, TestContext.class }) -@ActiveProfiles("test") -@TestPropertySource(properties = { "xplanbox.s3.bucket.validation=test-bucket-validation" }) +@TestPropertySource(value = "/s3Mock.properties", + properties = { "xplanbox.s3.bucket.validation=test-bucket-validation" }) +@ActiveProfiles({ "mock", "test" }) class ConfigHandlerTest { @Autowired diff --git a/xplan-validator/xplan-validator-api/src/test/java/de/latlon/xplanbox/api/validator/handler/v2/ConfigHandlerV2Test.java b/xplan-validator/xplan-validator-api/src/test/java/de/latlon/xplanbox/api/validator/handler/v2/ConfigHandlerV2Test.java index 59956e95a6257a4d4f70868b661da598d0c8ccce..872ef076f96da4604b067a2eaba512d87f329599 100644 --- a/xplan-validator/xplan-validator-api/src/test/java/de/latlon/xplanbox/api/validator/handler/v2/ConfigHandlerV2Test.java +++ b/xplan-validator/xplan-validator-api/src/test/java/de/latlon/xplanbox/api/validator/handler/v2/ConfigHandlerV2Test.java @@ -41,8 +41,9 @@ import org.springframework.test.context.junit.jupiter.SpringExtension; */ @ExtendWith(SpringExtension.class) @ContextConfiguration(classes = { ApplicationContext.class, TestContext.class }) -@ActiveProfiles("test") -@TestPropertySource(properties = { "xplanbox.s3.bucket.validation=test-bucket-validation" }) +@TestPropertySource(value = "/s3Mock.properties", + properties = { "xplanbox.s3.bucket.validation=test-bucket-validation" }) +@ActiveProfiles({ "mock", "test" }) class ConfigHandlerV2Test { @Autowired diff --git a/xplan-validator/xplan-validator-api/src/test/resources/s3Mock.properties b/xplan-validator/xplan-validator-api/src/test/resources/s3Mock.properties index 008ce1c398d14c8c6c2fa47fd3a457b22b0746c4..32c458100eddc1d6866f96b85037b729ffa4c7c9 100644 --- a/xplan-validator/xplan-validator-api/src/test/resources/s3Mock.properties +++ b/xplan-validator/xplan-validator-api/src/test/resources/s3Mock.properties @@ -20,6 +20,6 @@ ### xplanbox.s3.accessKeyId= xplanbox.s3.secretKey= -xplanbox.s3.bucket.validation=latlonvalidationtest +xplanbox.s3.bucketName=latlonxpbtest xplanbox.s3.region=eu-central-1 xplanbox.s3.endpoint.url=http://localhost diff --git a/xplan-validator/xplan-validator-executor/Dockerfile b/xplan-validator/xplan-validator-executor/Dockerfile index 689d2596b0b6b24630b4dd2e444685cbc3f40174..f0d9e7a6408b66f17ec8d939368359d2e4578c08 100644 --- a/xplan-validator/xplan-validator-executor/Dockerfile +++ b/xplan-validator/xplan-validator-executor/Dockerfile @@ -32,7 +32,6 @@ COPY --from=builder $JMX_EXPORTER_DIR $JMX_EXPORTER_DIR ENV DEEGREE_WORKSPACE_ROOT=/xplanbox/deegree \ JAVA_ADDITIONAL_ARG_APP="-Djavax.xml.transform.TransformerFactory=net.sf.saxon.TransformerFactoryImpl -Djts.overlay=ng -Duser.timezone=Europe/Berlin" \ JAVA_ADDITIONAL_ARG_JAVA17_EXPORTS="--add-exports=java.desktop/com.sun.imageio.spi=ALL-UNNAMED" \ - JAVA_ADDITIONAL_ARG_DISABLE_AWS_DEPRECATION="-Daws.java.v1.disableDeprecationAnnouncement=true" \ JAVA_ADDITIONAL_ARG_JMX_EXPORTER='-javaagent:$JMX_EXPORTER_DIR/jmx_prometheus_javaagent-1.0.1.jar=12345:$JMX_EXPORTER_DIR/jmx-exporter.config.yaml' \ XPLANBOX_CONFIG="/xplanbox/xplan-validator-config/" diff --git a/xplan-validator/xplan-validator-executor/src/test/java/de/latlon/xplanbox/validator/executor/PlanValidatorTest.java b/xplan-validator/xplan-validator-executor/src/test/java/de/latlon/xplanbox/validator/executor/PlanValidatorTest.java index 8fdee6dcd47a6ff20c3dd5f049cd52d927b49e89..8b8cac0c5153c5932a00c2e44d10778d4eeb959d 100644 --- a/xplan-validator/xplan-validator-executor/src/test/java/de/latlon/xplanbox/validator/executor/PlanValidatorTest.java +++ b/xplan-validator/xplan-validator-executor/src/test/java/de/latlon/xplanbox/validator/executor/PlanValidatorTest.java @@ -75,9 +75,8 @@ import org.springframework.test.context.bean.override.mockito.MockitoBean; */ @SpringBootTest(classes = { SpringBootApp.class }) @Import(TestS3Context.class) -@TestPropertySource( - properties = { "xplanbox.s3.bucketName=test-bucket", "xplanbox.s3.bucket.validation=test-bucket-validation" }) -@ActiveProfiles("test") +@ActiveProfiles({ "mock", "test" }) +@TestPropertySource("classpath:s3Mock.properties") class PlanValidatorTest { @TestConfiguration diff --git a/xplan-validator/xplan-validator-executor/src/test/java/de/latlon/xplanbox/validator/executor/config/TestS3Context.java b/xplan-validator/xplan-validator-executor/src/test/java/de/latlon/xplanbox/validator/executor/config/TestS3Context.java index 6c2ba9bc7302589258b73e4dbc95ea06c4838a35..1263347ae96c7d26547dd433d2f422ed45cb318e 100644 --- a/xplan-validator/xplan-validator-executor/src/test/java/de/latlon/xplanbox/validator/executor/config/TestS3Context.java +++ b/xplan-validator/xplan-validator-executor/src/test/java/de/latlon/xplanbox/validator/executor/config/TestS3Context.java @@ -8,34 +8,40 @@ * it under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. - * + * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * + * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. * #L% */ package de.latlon.xplanbox.validator.executor.config; -import com.amazonaws.auth.AWSCredentials; -import com.amazonaws.auth.AWSStaticCredentialsProvider; -import com.amazonaws.auth.AnonymousAWSCredentials; -import com.amazonaws.auth.BasicAWSCredentials; -import com.amazonaws.client.builder.AwsClientBuilder; -import com.amazonaws.services.s3.AmazonS3; -import com.amazonaws.services.s3.AmazonS3ClientBuilder; +import static software.amazon.awssdk.regions.Region.EU_CENTRAL_1; + +import java.net.URI; +import java.net.URISyntaxException; + import io.findify.s3mock.S3Mock; import jakarta.annotation.PreDestroy; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Primary; +import org.springframework.context.annotation.Profile; import org.springframework.test.util.TestSocketUtils; +import software.amazon.awssdk.auth.credentials.AwsBasicCredentials; +import software.amazon.awssdk.auth.credentials.StaticCredentialsProvider; +import software.amazon.awssdk.services.s3.S3Client; +import software.amazon.awssdk.services.s3.S3Configuration; +import software.amazon.awssdk.services.s3.model.CreateBucketRequest; /** + * Spring Configuration to enable usage of mock objects for integration tests. + * * @author <a href="mailto:goltz@lat-lon.de">Lyn Goltz </a> * @since 8.0 */ @@ -44,11 +50,12 @@ public class TestS3Context { private final int port = TestSocketUtils.findAvailableTcpPort(); - private AmazonS3 s3TestClient; + private S3Client s3TestClient; private S3Mock s3Mock; @Bean + @Profile("mock") public S3Mock s3Mock() { this.s3Mock = new S3Mock.Builder().withPort(port).withInMemoryBackend().build(); s3Mock.start(); @@ -57,28 +64,25 @@ public class TestS3Context { @Bean @Primary - public AmazonS3 s3Client(S3Mock s3Mock, @Value("${xplanbox.s3.bucketName}") String bucketName) { - AwsClientBuilder.EndpointConfiguration endpoint = new AwsClientBuilder.EndpointConfiguration( - "http://localhost:" + port, "eu-central-1"); - AmazonS3 client = AmazonS3ClientBuilder.standard() - .withPathStyleAccessEnabled(true) - .withEndpointConfiguration(endpoint) - .withCredentials(new AWSStaticCredentialsProvider(new AnonymousAWSCredentials())) + @Profile("mock") + public S3Client s3Client(S3Mock s3Mock, @Value("${xplanbox.s3.bucketName}") String bucketName) + throws URISyntaxException { + URI endpoint = new URI("http://localhost:" + port); + S3Client client = S3Client.builder() + .serviceConfiguration(S3Configuration.builder().pathStyleAccessEnabled(true).build()) + .endpointOverride(endpoint) + .credentialsProvider( + StaticCredentialsProvider.create(AwsBasicCredentials.create("accessKeyId", "secretKey"))) + .region(EU_CENTRAL_1) .build(); - client.createBucket(bucketName); + client.createBucket(CreateBucketRequest.builder().bucket(bucketName).build()); s3TestClient = client; return client; } - @Bean - @Primary - public AWSCredentials credentials() { - return new BasicAWSCredentials("accessKeyId", "secretKey"); - } - @PreDestroy public void shutdown() { - s3TestClient.shutdown(); + s3TestClient.close(); if (s3Mock != null) { s3Mock.stop(); } diff --git a/xplan-validator/xplan-validator-executor/src/test/java/de/latlon/xplanbox/validator/executor/handler/ValidationHandlerTest.java b/xplan-validator/xplan-validator-executor/src/test/java/de/latlon/xplanbox/validator/executor/handler/ValidationHandlerTest.java index fa36103d93aa83b7d3ff46c7d4ae5a159e245863..51fed615bcdc4904f3efe218bc59c0c6de852344 100644 --- a/xplan-validator/xplan-validator-executor/src/test/java/de/latlon/xplanbox/validator/executor/handler/ValidationHandlerTest.java +++ b/xplan-validator/xplan-validator-executor/src/test/java/de/latlon/xplanbox/validator/executor/handler/ValidationHandlerTest.java @@ -60,9 +60,8 @@ import org.springframework.test.context.bean.override.mockito.MockitoBean; */ @SpringBootTest(classes = { SpringBootApp.class }) @Import(TestS3Context.class) -@TestPropertySource( - properties = { "xplanbox.s3.bucketName=test-bucket", "xplanbox.s3.bucket.validation=test-bucket-validation" }) -@ActiveProfiles("test") +@ActiveProfiles({ "mock", "test" }) +@TestPropertySource("classpath:s3Mock.properties") public class ValidationHandlerTest { @MockitoBean diff --git a/xplan-validator/xplan-validator-executor/src/test/resources/s3Mock.properties b/xplan-validator/xplan-validator-executor/src/test/resources/s3Mock.properties new file mode 100644 index 0000000000000000000000000000000000000000..32c458100eddc1d6866f96b85037b729ffa4c7c9 --- /dev/null +++ b/xplan-validator/xplan-validator-executor/src/test/resources/s3Mock.properties @@ -0,0 +1,25 @@ +### +# #%L +# xplan-manager-core - XPlan Manager Core Komponente +# %% +# Copyright (C) 2008 - 2025 Freie und Hansestadt Hamburg, developed by lat/lon gesellschaft für raumbezogene Informationssysteme mbH +# %% +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# #L% +### +xplanbox.s3.accessKeyId= +xplanbox.s3.secretKey= +xplanbox.s3.bucketName=latlonxpbtest +xplanbox.s3.region=eu-central-1 +xplanbox.s3.endpoint.url=http://localhost diff --git a/xplan-validator/xplan-validator-storage/pom.xml b/xplan-validator/xplan-validator-storage/pom.xml index 08221152c58e71dcf94db213ed1294ade21234a0..2642d85aae840590f631290790ef233db4daeb6f 100644 --- a/xplan-validator/xplan-validator-storage/pom.xml +++ b/xplan-validator/xplan-validator-storage/pom.xml @@ -30,8 +30,8 @@ </dependency> <!-- aws --> <dependency> - <groupId>com.amazonaws</groupId> - <artifactId>aws-java-sdk-s3</artifactId> + <groupId>software.amazon.awssdk</groupId> + <artifactId>s3</artifactId> </dependency> <!-- test --> <dependency> diff --git a/xplan-validator/xplan-validator-storage/src/main/java/de/latlon/xplanbox/validator/storage/config/AmazonS3ValidationContext.java b/xplan-validator/xplan-validator-storage/src/main/java/de/latlon/xplanbox/validator/storage/config/AmazonS3ValidationContext.java index a144fc0b1d5d3ce39b340928ef60dd6f3551398c..b2141245721bea23ea39cb2b95997efd679285b8 100644 --- a/xplan-validator/xplan-validator-storage/src/main/java/de/latlon/xplanbox/validator/storage/config/AmazonS3ValidationContext.java +++ b/xplan-validator/xplan-validator-storage/src/main/java/de/latlon/xplanbox/validator/storage/config/AmazonS3ValidationContext.java @@ -20,7 +20,6 @@ */ package de.latlon.xplanbox.validator.storage.config; -import com.amazonaws.services.s3.AmazonS3; import de.latlon.xplan.commons.s3.S3Storage; import de.latlon.xplan.commons.s3.StorageException; import de.latlon.xplan.commons.s3.config.AmazonS3ReadOnlyContext; @@ -30,6 +29,7 @@ import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Import; +import software.amazon.awssdk.services.s3.S3Client; /** * Spring configuration for using AWS S3 as a storage. @@ -48,7 +48,7 @@ public class AmazonS3ValidationContext { } @Bean - public S3Storage s3Storage(AmazonS3 s3Client, @Value("${xplanbox.s3.bucket.validation}") String bucketName) + public S3Storage s3Storage(S3Client s3Client, @Value("${xplanbox.s3.bucket.validation}") String bucketName) throws StorageException { S3Storage s3Storage = new S3Storage(s3Client, bucketName); s3Storage.setBucketExpirationDate("deleteAfter30d", 30); diff --git a/xplan-validator/xplan-validator-storage/src/main/java/de/latlon/xplanbox/validator/storage/s3/S3PlanValidationExecutionStorage.java b/xplan-validator/xplan-validator-storage/src/main/java/de/latlon/xplanbox/validator/storage/s3/S3PlanValidationExecutionStorage.java index e60453507b5b7fa0ad48f9d21049e4d9d0ca3830..ab4f0898a22fbc5687a9affc88b373e148fb92e9 100644 --- a/xplan-validator/xplan-validator-storage/src/main/java/de/latlon/xplanbox/validator/storage/s3/S3PlanValidationExecutionStorage.java +++ b/xplan-validator/xplan-validator-storage/src/main/java/de/latlon/xplanbox/validator/storage/s3/S3PlanValidationExecutionStorage.java @@ -8,12 +8,12 @@ * it under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. - * + * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * + * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. * #L% @@ -27,14 +27,13 @@ import java.nio.file.Path; import java.util.Map; import java.util.Map.Entry; -import com.amazonaws.services.s3.model.PutObjectResult; -import com.amazonaws.services.s3.model.S3ObjectSummary; import de.latlon.xplan.commons.s3.S3Metadata; import de.latlon.xplan.commons.s3.S3Object; import de.latlon.xplan.commons.s3.S3Storage; import de.latlon.xplan.commons.s3.StorageException; import de.latlon.xplanbox.validator.storage.StoredValidationReport; import de.latlon.xplanbox.validator.storage.ValidationExecutionStorage; +import software.amazon.awssdk.services.s3.model.PutObjectResponse; /** * @author <a href="mailto:goltz@lat-lon.de">Lyn Goltz </a> @@ -68,8 +67,10 @@ public class S3PlanValidationExecutionStorage extends ValidationExecutionStorage @Override protected void removeFromStore(Key key) { - S3ObjectSummary object = new S3ObjectSummary(); - object.setKey(key.toFileName()); + software.amazon.awssdk.services.s3.model.S3Object object = software.amazon.awssdk.services.s3.model.S3Object + .builder() + .key(key.toFileName()) + .build(); s3Storage.deleteObject(object); } @@ -88,12 +89,14 @@ public class S3PlanValidationExecutionStorage extends ValidationExecutionStorage @Override public StoredValidationReport saveValidationResult(String uuid, Map<ReportType, Path> reports) throws StorageException { - PutObjectResult lastPutObjectResult = null; + PutObjectResponse lastPutObjectResult = null; for (Entry<ReportType, Path> entry : reports.entrySet()) { String fileName = Key.report(uuid, entry.getKey()).toFileName(); lastPutObjectResult = s3Storage.insertObject(fileName, entry.getValue()); } - return new StoredValidationReport(lastPutObjectResult.getExpirationTime()); + // TODO + System.out.println(lastPutObjectResult.expiration()); + return new StoredValidationReport(null); } } diff --git a/xplan-validator/xplan-validator-storage/src/test/java/de/latlon/xplanbox/validator/storage/s3/S3ValidationExecutionStorageIT.java b/xplan-validator/xplan-validator-storage/src/test/java/de/latlon/xplanbox/validator/storage/s3/S3ValidationExecutionStorageIT.java index 893bda25c850f9eeaa696900186cd4dcf85a8342..47a94060b36eb0b6eb0f7e8fa2cbb5409cec7298 100644 --- a/xplan-validator/xplan-validator-storage/src/test/java/de/latlon/xplanbox/validator/storage/s3/S3ValidationExecutionStorageIT.java +++ b/xplan-validator/xplan-validator-storage/src/test/java/de/latlon/xplanbox/validator/storage/s3/S3ValidationExecutionStorageIT.java @@ -54,8 +54,8 @@ import org.springframework.test.context.junit.jupiter.SpringExtension; * @since 8.0 */ @ExtendWith(SpringExtension.class) -@ContextConfiguration(classes = { AmazonS3ValidationContext.class, AmazonS3TestContext.class }) -@ActiveProfiles({ "mock" }) +@ContextConfiguration(classes = { AmazonS3ValidationContext.class, TestS3Context.class }) +@ActiveProfiles({ "mock", "test" }) @TestPropertySource("classpath:s3Mock.properties") public class S3ValidationExecutionStorageIT { diff --git a/xplan-validator/xplan-validator-storage/src/test/java/de/latlon/xplanbox/validator/storage/s3/S3ValidationExecutionStorageTest.java b/xplan-validator/xplan-validator-storage/src/test/java/de/latlon/xplanbox/validator/storage/s3/S3ValidationExecutionStorageTest.java index b754e00017b75302e8cfe88e380f82f93b184ee0..772fd70c0a6128f57177d2612be7548c172c4307 100644 --- a/xplan-validator/xplan-validator-storage/src/test/java/de/latlon/xplanbox/validator/storage/s3/S3ValidationExecutionStorageTest.java +++ b/xplan-validator/xplan-validator-storage/src/test/java/de/latlon/xplanbox/validator/storage/s3/S3ValidationExecutionStorageTest.java @@ -8,12 +8,12 @@ * it under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. - * + * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * + * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. * #L% @@ -25,17 +25,12 @@ import static de.latlon.xplanbox.validator.storage.ValidationExecutionStorage.Fi import static de.latlon.xplanbox.validator.storage.ValidationExecutionStorage.FileType.STATUS; import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyString; -import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; -import java.io.File; import java.io.IOException; -import java.io.InputStream; import java.net.URISyntaxException; import java.net.URL; import java.nio.file.Path; @@ -44,15 +39,18 @@ import java.util.HashMap; import java.util.Map; import java.util.UUID; -import com.amazonaws.services.s3.AmazonS3; -import com.amazonaws.services.s3.model.ObjectMetadata; -import com.amazonaws.services.s3.model.PutObjectResult; import de.latlon.xplan.commons.s3.S3Storage; import de.latlon.xplan.commons.s3.StorageException; import de.latlon.xplanbox.validator.storage.ValidationExecutionStorage.Key; import de.latlon.xplanbox.validator.storage.ValidationExecutionStorage.ReportType; import org.junit.jupiter.api.Test; import org.mockito.ArgumentCaptor; +import software.amazon.awssdk.core.sync.RequestBody; +import software.amazon.awssdk.services.s3.S3Client; +import software.amazon.awssdk.services.s3.model.HeadBucketRequest; +import software.amazon.awssdk.services.s3.model.HeadBucketResponse; +import software.amazon.awssdk.services.s3.model.PutObjectRequest; +import software.amazon.awssdk.services.s3.model.PutObjectResponse; /** * @author <a href="mailto:goltz@lat-lon.de">Lyn Goltz </a> @@ -64,46 +62,51 @@ class S3ValidationExecutionStorageTest { @Test void testAddPlanToValidate_gml() throws IOException, URISyntaxException, StorageException { - AmazonS3 client = spy(AmazonS3.class); + S3Client client = createS3ClientSpy(); S3Storage s3Storage = new S3Storage(client, BUCKET_NAME); S3PlanValidationExecutionStorage validationExecutionStorage = new S3PlanValidationExecutionStorage(s3Storage); URL xplanGml = getClass().getResource("/xplan.gml"); String key = validationExecutionStorage.addPlanToValidate(Paths.get(xplanGml.toURI()), VALIDATION_REQUESTED); - ArgumentCaptor<String> keyCaptor = ArgumentCaptor.forClass(String.class); + ArgumentCaptor<HeadBucketRequest> headBucketRequestCaptor = ArgumentCaptor.forClass(HeadBucketRequest.class); + ArgumentCaptor<PutObjectRequest> putObjectRequestCaptor = ArgumentCaptor.forClass(PutObjectRequest.class); - verify(client, times(3)).doesBucketExistV2(eq(BUCKET_NAME)); - verify(client, times(2)).putObject(eq(BUCKET_NAME), keyCaptor.capture(), any(InputStream.class), - any(ObjectMetadata.class)); - verify(client).putObject(eq(BUCKET_NAME), keyCaptor.capture(), any(File.class)); + verify(client, times(3)).headBucket(headBucketRequestCaptor.capture()); + verify(client, times(3)).putObject(putObjectRequestCaptor.capture(), any(RequestBody.class)); - assertThat(keyCaptor.getAllValues()).containsExactlyInAnyOrder(key, key + DETAILS.getSuffix(), - key + STATUS.getSuffix()); + assertThat(headBucketRequestCaptor.getAllValues()).map(HeadBucketRequest::bucket) + .containsExactlyInAnyOrder(BUCKET_NAME, BUCKET_NAME, BUCKET_NAME); + assertThat(putObjectRequestCaptor.getAllValues()).map(PutObjectRequest::bucket) + .containsExactlyInAnyOrder(BUCKET_NAME, BUCKET_NAME, BUCKET_NAME); + assertThat(putObjectRequestCaptor.getAllValues()).map(PutObjectRequest::key) + .containsExactlyInAnyOrder(key, key + DETAILS.getSuffix(), key + STATUS.getSuffix()); } @Test void testAddPlanToValidate_zip() throws IOException, URISyntaxException, StorageException { - AmazonS3 client = spy(AmazonS3.class); + S3Client client = createS3ClientSpy(); S3Storage s3Storage = new S3Storage(client, BUCKET_NAME); S3PlanValidationExecutionStorage validationExecutionStorage = new S3PlanValidationExecutionStorage(s3Storage); URL xplanGml = getClass().getResource("/BPlan002_5-3.zip"); String key = validationExecutionStorage.addPlanToValidate(Paths.get(xplanGml.toURI()), VALIDATION_REQUESTED); - ArgumentCaptor<String> keyCaptor = ArgumentCaptor.forClass(String.class); + ArgumentCaptor<HeadBucketRequest> headBucketRequestCaptor = ArgumentCaptor.forClass(HeadBucketRequest.class); + ArgumentCaptor<PutObjectRequest> putObjectRequestCaptor = ArgumentCaptor.forClass(PutObjectRequest.class); - verify(client, times(3)).doesBucketExistV2(eq(BUCKET_NAME)); - verify(client, times(2)).putObject(eq(BUCKET_NAME), keyCaptor.capture(), any(InputStream.class), - any(ObjectMetadata.class)); - verify(client).putObject(eq(BUCKET_NAME), keyCaptor.capture(), any(File.class)); + verify(client, times(3)).headBucket(headBucketRequestCaptor.capture()); + verify(client, times(3)).putObject(putObjectRequestCaptor.capture(), any(RequestBody.class)); - assertThat(keyCaptor.getAllValues()).containsExactlyInAnyOrder(key, key + DETAILS.getSuffix(), - key + STATUS.getSuffix()); + assertThat(headBucketRequestCaptor.getAllValues()).map(HeadBucketRequest::bucket) + .containsExactlyInAnyOrder(BUCKET_NAME, BUCKET_NAME, BUCKET_NAME); + assertThat(putObjectRequestCaptor.getAllValues()).map(PutObjectRequest::bucket) + .containsExactlyInAnyOrder(BUCKET_NAME, BUCKET_NAME, BUCKET_NAME); + assertThat(putObjectRequestCaptor.getAllValues()).map(PutObjectRequest::key) + .containsExactlyInAnyOrder(key, key + DETAILS.getSuffix(), key + STATUS.getSuffix()); } @Test void testSaveValidationResult() throws URISyntaxException, StorageException { - AmazonS3 client = spy(AmazonS3.class); - when(client.putObject(anyString(), anyString(), any(File.class))).thenReturn(mock(PutObjectResult.class)); + S3Client client = createS3ClientSpy(); S3Storage s3Storage = new S3Storage(client, BUCKET_NAME); S3PlanValidationExecutionStorage validationExecutionStorage = new S3PlanValidationExecutionStorage(s3Storage); URL xplanGml = getClass().getResource("/BPlan002_5-3.zip"); @@ -114,13 +117,27 @@ class S3ValidationExecutionStorageTest { reports.put(ReportType.PDF, Paths.get(xplanGml.toURI())); validationExecutionStorage.saveValidationResult(uuid, reports); - ArgumentCaptor<String> keyCaptor = ArgumentCaptor.forClass(String.class); + ArgumentCaptor<HeadBucketRequest> headBucketRequestCaptor = ArgumentCaptor.forClass(HeadBucketRequest.class); + ArgumentCaptor<PutObjectRequest> putObjectRequestCaptor = ArgumentCaptor.forClass(PutObjectRequest.class); - verify(client, times(2)).doesBucketExistV2(eq(BUCKET_NAME)); - verify(client, times(2)).putObject(eq(BUCKET_NAME), keyCaptor.capture(), any(File.class)); + verify(client, times(2)).headBucket(headBucketRequestCaptor.capture()); + verify(client, times(2)).putObject(putObjectRequestCaptor.capture(), any(RequestBody.class)); - assertThat(keyCaptor.getAllValues()).containsExactlyInAnyOrder(Key.report(uuid, ReportType.PDF).toFileName(), - Key.report(uuid, ReportType.JSON).toFileName()); + assertThat(headBucketRequestCaptor.getAllValues()).map(HeadBucketRequest::bucket) + .containsExactlyInAnyOrder(BUCKET_NAME, BUCKET_NAME); + assertThat(putObjectRequestCaptor.getAllValues()).map(PutObjectRequest::bucket) + .containsExactlyInAnyOrder(BUCKET_NAME, BUCKET_NAME); + assertThat(putObjectRequestCaptor.getAllValues()).map(PutObjectRequest::key) + .containsExactlyInAnyOrder(Key.report(uuid, ReportType.PDF).toFileName(), + Key.report(uuid, ReportType.JSON).toFileName()); + } + + private static S3Client createS3ClientSpy() { + S3Client client = spy(S3Client.class); + doReturn(HeadBucketResponse.builder().build()).when(client).headBucket(any(HeadBucketRequest.class)); + doReturn(PutObjectResponse.builder().build()).when(client) + .putObject(any(PutObjectRequest.class), any(RequestBody.class)); + return client; } } diff --git a/xplan-validator/xplan-validator-storage/src/test/java/de/latlon/xplanbox/validator/storage/s3/AmazonS3TestContext.java b/xplan-validator/xplan-validator-storage/src/test/java/de/latlon/xplanbox/validator/storage/s3/TestS3Context.java similarity index 60% rename from xplan-validator/xplan-validator-storage/src/test/java/de/latlon/xplanbox/validator/storage/s3/AmazonS3TestContext.java rename to xplan-validator/xplan-validator-storage/src/test/java/de/latlon/xplanbox/validator/storage/s3/TestS3Context.java index c5f243cf033e17db92cfe782ed433a42b8a89701..a5469ce4f452cf366497f6192e2c29b30bb090e1 100644 --- a/xplan-validator/xplan-validator-storage/src/test/java/de/latlon/xplanbox/validator/storage/s3/AmazonS3TestContext.java +++ b/xplan-validator/xplan-validator-storage/src/test/java/de/latlon/xplanbox/validator/storage/s3/TestS3Context.java @@ -8,32 +8,36 @@ * it under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. - * + * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * + * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. * #L% */ package de.latlon.xplanbox.validator.storage.s3; -import com.amazonaws.auth.AWSStaticCredentialsProvider; -import com.amazonaws.auth.AnonymousAWSCredentials; -import com.amazonaws.client.builder.AwsClientBuilder; -import com.amazonaws.services.s3.AmazonS3; -import com.amazonaws.services.s3.AmazonS3ClientBuilder; +import static software.amazon.awssdk.regions.Region.EU_CENTRAL_1; + +import java.net.URI; +import java.net.URISyntaxException; + import io.findify.s3mock.S3Mock; import jakarta.annotation.PreDestroy; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Primary; import org.springframework.context.annotation.Profile; import org.springframework.test.util.TestSocketUtils; +import software.amazon.awssdk.auth.credentials.AwsBasicCredentials; +import software.amazon.awssdk.auth.credentials.StaticCredentialsProvider; +import software.amazon.awssdk.services.s3.S3Client; +import software.amazon.awssdk.services.s3.S3Configuration; +import software.amazon.awssdk.services.s3.model.CreateBucketRequest; /** * Spring Configuration to enable usage of mock objects for integration tests. @@ -42,20 +46,18 @@ import org.springframework.test.util.TestSocketUtils; * @author <a href="mailto:friebe@lat-lon.de">Torsten Friebe</a> */ @Configuration -public class AmazonS3TestContext { +public class TestS3Context { - @Autowired(required = false) - private S3Mock s3Mock; + private final int port = TestSocketUtils.findAvailableTcpPort(); - @Autowired - private AmazonS3 s3TestClient; + private S3Client s3TestClient; - private final int port = TestSocketUtils.findAvailableTcpPort(); + private S3Mock s3Mock; @Bean @Profile("mock") public S3Mock s3Mock() { - S3Mock s3Mock = new S3Mock.Builder().withPort(port).withInMemoryBackend().build(); + this.s3Mock = new S3Mock.Builder().withPort(port).withInMemoryBackend().build(); s3Mock.start(); return s3Mock; } @@ -63,23 +65,24 @@ public class AmazonS3TestContext { @Bean @Primary @Profile("mock") - public AmazonS3 s3TestClient(@Value("${xplanbox.s3.region}") String signingRegion, - @Value("${xplanbox.s3.bucket.validation}") String bucketName, - @Value("${xplanbox.s3.endpoint.url}") String url) { - AwsClientBuilder.EndpointConfiguration endpoint = new AwsClientBuilder.EndpointConfiguration(url + ":" + port, - signingRegion); - AmazonS3 client = AmazonS3ClientBuilder.standard() - .withPathStyleAccessEnabled(true) - .withEndpointConfiguration(endpoint) - .withCredentials(new AWSStaticCredentialsProvider(new AnonymousAWSCredentials())) + public S3Client s3TestClient(S3Mock s3Mock, @Value("${xplanbox.s3.bucket.validation}") String bucketName) + throws URISyntaxException { + URI endpoint = new URI("http://localhost:" + port); + S3Client client = S3Client.builder() + .serviceConfiguration(S3Configuration.builder().pathStyleAccessEnabled(true).build()) + .endpointOverride(endpoint) + .credentialsProvider( + StaticCredentialsProvider.create(AwsBasicCredentials.create("accessKeyId", "secretKey"))) + .region(EU_CENTRAL_1) .build(); - client.createBucket(bucketName); + client.createBucket(CreateBucketRequest.builder().bucket(bucketName).build()); + s3TestClient = client; return client; } @PreDestroy public void shutdown() { - s3TestClient.shutdown(); + s3TestClient.close(); if (s3Mock != null) { s3Mock.stop(); } diff --git a/xplan-validator/xplan-validator-web/pom.xml b/xplan-validator/xplan-validator-web/pom.xml index 49997fec8ca5b4aeaec4cf907b7bcce6a8e98561..9136c48b9ef3f8fef985e0f502a321c9544554a8 100644 --- a/xplan-validator/xplan-validator-web/pom.xml +++ b/xplan-validator/xplan-validator-web/pom.xml @@ -284,7 +284,7 @@ <id>docker</id> <properties> <docker-image.skip>false</docker-image.skip> - <docker-contextTarFile.expectedSizeInMat10pct>72</docker-contextTarFile.expectedSizeInMat10pct> + <docker-contextTarFile.expectedSizeInMat10pct>86</docker-contextTarFile.expectedSizeInMat10pct> </properties> <dependencies> <dependency> <!-- faked maven dependency to be after base docker image in the reactor build --> diff --git a/xplan-webservices/xplan-webservices-mapproxy/xplan-mapproxy-config/src/main/resources/mapproxy.yaml b/xplan-webservices/xplan-webservices-mapproxy/xplan-mapproxy-config/src/main/resources/mapproxy.yaml index 64b2d3ef89a5bbe4139ba635a4cd39adc614833e..2f19f92a59a356d2b2bdc4aa8a3027e7f9de1fcf 100644 --- a/xplan-webservices/xplan-webservices-mapproxy/xplan-mapproxy-config/src/main/resources/mapproxy.yaml +++ b/xplan-webservices/xplan-webservices-mapproxy/xplan-mapproxy-config/src/main/resources/mapproxy.yaml @@ -336,7 +336,7 @@ sources: xplan-mapserver: <<: *wms_cfg req: - url: ${XPLAN_MAPSERVER_URL_INTERNAL}/mapserver? + url: ${XPLAN_MAPSERVER_URL_INTERNAL}/xplan-mapserver? transparent: true bplan-wms: <<: *wms_cfg @@ -385,7 +385,7 @@ globals: lock_dir: "./cache_data/locks" tile_lock_dir: "./cache_data/tile_locks" s3: - endpoint_url: https://${XPLAN_S3_ENDPOINT} + endpoint_url: ${XPLAN_S3_ENDPOINT} bucket_name: ${XPLAN_S3_BUCKET_MAPPROXYCACHE} region_name: ${XPLAN_S3_REGION} image: diff --git a/xplan-webservices/xplan-webservices-mapproxy/xplan-mapproxy-docker/Dockerfile b/xplan-webservices/xplan-webservices-mapproxy/xplan-mapproxy-docker/Dockerfile index 5d3ecbd9095bf2b494c6586cbfed1e8f764c5d1e..1d5bd960ae5778eecbd9c735d9f39ec69d1c4b75 100644 --- a/xplan-webservices/xplan-webservices-mapproxy/xplan-mapproxy-docker/Dockerfile +++ b/xplan-webservices/xplan-webservices-mapproxy/xplan-mapproxy-docker/Dockerfile @@ -1,6 +1,6 @@ FROM python:3.12-slim -ARG MAPPROXY_VERSION=1.16.0 +ARG MAPPROXY_VERSION=3.1.3 ARG BUILD_DATE=? ARG DOCKER_IMAGE_NAME=? ARG GIT_REVISION=? @@ -40,7 +40,7 @@ RUN apt update && apt -y install --no-install-recommends \ apt-get clean && \ rm -rf /var/lib/apt/lists/* && \ python -m venv --system-site-packages /srv/mapproxy/venv && \ - pip install mapproxy==$MAPPROXY_VERSION uwsgi pyproj pillow pyyaml boto3==1.35.99 shapely==1.7.1 setuptools && \ + pip install mapproxy==$MAPPROXY_VERSION uwsgi riak==2.4.2 redis azure-storage-blob boto3==1.35.99 Shapely && \ pip cache purge && \ addgroup --gid 1001 mapproxy && \ adduser --uid 1001 --shell /bin/false --gid 1001 --no-create-home --disabled-login mapproxy && \ diff --git a/xplan-webservices/xplan-webservices-mapserver/xplan-mapserver-config/src/main/resources/common.txt b/xplan-webservices/xplan-webservices-mapserver/xplan-mapserver-config/src/main/resources/common.txt index 0a060d3fcf4fa5e2f56869b81716368dcbf5ad4d..b0f7c2bf8793af4d1a046a3ee704c1087756f932 100644 --- a/xplan-webservices/xplan-webservices-mapserver/xplan-mapserver-config/src/main/resources/common.txt +++ b/xplan-webservices/xplan-webservices-mapserver/xplan-mapserver-config/src/main/resources/common.txt @@ -30,7 +30,7 @@ IMAGETYPE png CONFIG "AWS_ACCESS_KEY_ID" "$AWS_ACCESS_KEY_ID" CONFIG "AWS_SECRET_ACCESS_KEY" "$AWS_SECRET_ACCESS_KEY" CONFIG "AWS_REGION" "$AWS_REGION" -CONFIG "AWS_S3_ENDPOINT" "$AWS_S3_ENDPOINT" +CONFIG "AWS_S3_ENDPOINT" "$AWS_S3_ENDPOINT_WITHOUT_PROTOCOL" SHAPEPATH "/vsis3/$XPLAN_S3_BUCKET_ATTACHMENTS" OUTPUTFORMAT diff --git a/xplan-webservices/xplan-webservices-mapserver/xplan-mapserver-config/src/main/resources/internal.map b/xplan-webservices/xplan-webservices-mapserver/xplan-mapserver-config/src/main/resources/internal.map index 7f25be5a1d7e8b3c43e3409bb4f9e015fd0fa00c..4e0022687abe474e832ba891ca7a648c3442acdf 100644 --- a/xplan-webservices/xplan-webservices-mapserver/xplan-mapserver-config/src/main/resources/internal.map +++ b/xplan-webservices/xplan-webservices-mapserver/xplan-mapserver-config/src/main/resources/internal.map @@ -29,7 +29,7 @@ MAP IMAGEPATH "/ms4w/tmp/ms_tmp/" IMAGEURL "/ms_tmp/" METADATA - "wms_onlineresource" "${XPLAN_MAPSERVER_URL_INTERNAL}/mapserver?map=/etc/mapserver/internal.map" + "wms_onlineresource" "${XPLAN_MAPSERVER_URL_INTERNAL}/xplan-mapserver?map=/etc/mapserver/internal.map" "wms_title" "xPlanBox Rasterdaten" "wms_srs" "EPSG:25832" "wms_enable_request" "*" diff --git a/xplan-webservices/xplan-webservices-mapserver/xplan-mapserver-docker/Dockerfile b/xplan-webservices/xplan-webservices-mapserver/xplan-mapserver-docker/Dockerfile index 8df858e0b7ccb92fae0d839fb5e1d48d000e2ec2..22e84366184ca74ee310bf28bfd4c18725189562 100644 --- a/xplan-webservices/xplan-webservices-mapserver/xplan-mapserver-docker/Dockerfile +++ b/xplan-webservices/xplan-webservices-mapserver/xplan-mapserver-docker/Dockerfile @@ -1,5 +1,5 @@ -# latest linux/amd64 on 21.11.23 -FROM camptocamp/mapserver@sha256:0ed39cd88641ea384f7ec3ae2cff02c841d7e20d5daea2c4d567e21e53d9c0c2 +# latest camptocamp/mapserver:8.4-gdal3.10 on 06.02.25 +FROM camptocamp/mapserver@sha256:521c49c590a3382c98e05995e921fa800b64bf901f3118c33b705d2ef096b434 ARG BUILD_DATE=? ARG DOCKER_IMAGE_NAME=? ARG GIT_REVISION=? @@ -17,9 +17,10 @@ LABEL "org.opencontainers.image.created"="$BUILD_DATE" \ "org.opencontainers.image.version"="$XPLANBOX_VERSION" \ "maintainer"="" -ENV XPLAN_SERVICES_WMS_MAXWIDTH=3840 +ENV XPLAN_SERVICES_WMS_MAXWIDTH=3840 \ + MAPSERVER_BASE_PATH=/xplan-mapserver \ + TZ=Europe/Berlin -ENV TZ=Europe/Berlin RUN apt-get update && DEBIAN_FRONTEND=noninteractive apt-get -y install tzdata gettext-base RUN mkdir -p /xplan-mapserver-docker \ diff --git a/xplan-webservices/xplan-webservices-mapserver/xplan-mapserver-docker/startupWithConfiguredMapserver.sh b/xplan-webservices/xplan-webservices-mapserver/xplan-mapserver-docker/startupWithConfiguredMapserver.sh index ce6c47bf7f021987b49938ab458958d9725054c5..f59324391e66e92765071f0fe491b5916b12e15e 100755 --- a/xplan-webservices/xplan-webservices-mapserver/xplan-mapserver-docker/startupWithConfiguredMapserver.sh +++ b/xplan-webservices/xplan-webservices-mapserver/xplan-mapserver-docker/startupWithConfiguredMapserver.sh @@ -16,8 +16,8 @@ fi echo "[$(date -Iseconds)] Initializing mapserver config ..." echo "[$(date -Iseconds)] MapProxy config initialization..." - -defined_envs="$(printf '${%s} ' $(env | cut -d'=' -f1))" +defined_envs="$(printf '${%s} ' $(env | cut -d'=' -f1)) \${AWS_S3_ENDPOINT_WITHOUT_PROTOCOL}" +export AWS_S3_ENDPOINT_WITHOUT_PROTOCOL="$(echo $AWS_S3_ENDPOINT | sed s/'http[s]\?:\/\/'//)" TARGET_DIR="$(dirname "${MS_MAPFILE}")" for FILE in /xplan-mapserver-docker/xplan-mapserver-config/*; do diff --git a/xplan-webservices/xplan-webservices-validator-wms/src/test/resources/de/latlon/xplan/validator/wms/libs.expected.txt b/xplan-webservices/xplan-webservices-validator-wms/src/test/resources/de/latlon/xplan/validator/wms/libs.expected.txt index 7ec8d43bad5fd880d2ad8f7fb25ac4bd767ce360..b34be6138e9db32c2d07b646862e4b2ee48ca1e4 100644 --- a/xplan-webservices/xplan-webservices-validator-wms/src/test/resources/de/latlon/xplan/validator/wms/libs.expected.txt +++ b/xplan-webservices/xplan-webservices-validator-wms/src/test/resources/de/latlon/xplan/validator/wms/libs.expected.txt @@ -1,12 +1,16 @@ accessors-smart-2.5.1.jar aircompressor-0.27.jar angus-activation-2.0.2.jar +annotations-2.30.10.jar antlr-runtime-3.5.3.jar +apache-client-2.30.10.jar apache-mime4j-core-0.8.6.jar +arns-2.30.10.jar asm-9.6.jar -aws-java-sdk-core-1.12.780.jar -aws-java-sdk-kms-1.12.780.jar -aws-java-sdk-s3-1.12.780.jar +auth-2.30.10.jar +aws-core-2.30.10.jar +aws-query-protocol-2.30.10.jar +aws-xml-protocol-2.30.10.jar axiom-api-1.4.0.jar axiom-impl-1.4.0.jar batik-anim-1.17.jar @@ -29,6 +33,8 @@ batik-util-1.17.jar batik-xml-1.17.jar cache-api-1.1.1.jar checker-qual-3.48.3.jar +checksums-2.30.10.jar +checksums-spi-2.30.10.jar commons-beanutils-1.9.4.jar commons-cli-1.2.jar commons-codec-1.17.2.jar @@ -40,10 +46,11 @@ commons-fileupload2-core-2.0.0-M2.jar commons-fileupload2-jakarta-servlet6-2.0.0-M2.jar commons-io-2.18.0.jar commons-lang-2.6.jar -commons-logging-1.1.3.jar +commons-logging-1.2.jar commons-math-2.2.jar commons-pool2-2.12.0.jar com.sun.xml.bind-jaxb-core-4.0.5.jar +crt-core-2.30.10.jar deegree-connectionprovider-datasource-3.6.0-SNAPSHOT.jar deegree-core-annotations-3.6.0-SNAPSHOT.jar deegree-core-base-3.6.0-SNAPSHOT.jar @@ -108,14 +115,22 @@ deegree-tilestore-remotewms-3.6.0-SNAPSHOT.jar deegree-tilestore-remotewmts-3.6.0-SNAPSHOT.jar deegree-webservices-3.6.0-SNAPSHOT.jar ehcache-3.10.8-jakarta.jar +endpoints-spi-2.30.10.jar error_prone_annotations-2.27.0.jar FastInfoset-1.2.18.jar +eventstream-1.0.1.jar gdal-3.6.0.jar gson-2.11.0.jar h2-2.3.232.jar +http-auth-2.30.10.jar +http-auth-aws-2.30.10.jar +http-auth-aws-eventstream-2.30.10.jar +http-auth-spi-2.30.10.jar +http-client-spi-2.30.10.jar httpclient-4.5.13.jar httpclient-4.5.14.jar httpcore-4.4.16.jar +identity-spi-2.30.10.jar imageio-ext-geocore-1.4.14.jar imageio-ext-streams-1.4.14.jar imageio-ext-tiff-1.4.14.jar @@ -124,7 +139,6 @@ istack-commons-runtime-4.1.2.jar jackson-annotations-2.18.2.jar jackson-core-2.18.2.jar jackson-databind-2.18.2.jar -jackson-dataformat-cbor-2.18.2.jar jackson-dataformat-yaml-2.18.2.jar jai-codec-1.1.3.jar jai-core-1.1.3.jar @@ -148,11 +162,10 @@ jaxb-runtime-4.0.5.jar jaxen-2.0.0.jar jcl-over-slf4j-2.0.16.jar jgridshift-core-1.3.1.jar -jmespath-java-1.12.780.jar -joda-time-2.12.7.jar jogl-1.1.2.jar json-path-2.9.0.jar json-smart-2.5.1.jar +json-utils-2.30.10.jar jts-core-1.20.0.jar jul-to-slf4j-2.0.16.jar junidecode-0.4.1.jar @@ -162,20 +175,42 @@ log4j-layout-template-json-2.24.3.jar log4j-slf4j2-impl-2.24.3.jar log4j-web-2.24.3.jar mchange-commons-java-0.2.15.jar +metrics-spi-2.30.10.jar micrometer-commons-1.14.3.jar micrometer-observation-1.14.3.jar +netty-buffer-4.1.117.Final.jar +netty-codec-4.1.117.Final.jar +netty-codec-http2-4.1.117.Final.jar +netty-codec-http-4.1.117.Final.jar +netty-common-4.1.117.Final.jar +netty-handler-4.1.117.Final.jar +netty-nio-client-2.30.10.jar +netty-resolver-4.1.117.Final.jar +netty-transport-4.1.117.Final.jar +netty-transport-classes-epoll-4.1.117.Final.jar +netty-transport-native-unix-common-4.1.117.Final.jar org.glassfish.jaxb-jaxb-core-4.0.5.jar postgis-geometry-2023.1.0.jar postgis-jdbc-2023.1.0.jar postgresql-42.7.5.jar primefaces-14.0.7-jakarta.jar primefaces-extensions-14.0.7.1-jakarta.jar +profiles-2.30.10.jar +protocol-core-2.30.10.jar quartz-2.3.2.jar +reactive-streams-1.0.4.jar +regions-2.30.10.jar +retries-2.30.10.jar +retries-spi-2.30.10.jar Saxon-HE-9.9.1-8.jar +s3-2.30.10.jar +sdk-core-2.30.10.jar slf4j-api-2.0.16.jar snakeyaml-2.3.jar spring-aop-6.2.2.jar spring-beans-6.2.2.jar +spring-boot-3.4.2.jar +spring-boot-autoconfigure-3.4.2.jar spring-context-6.2.2.jar spring-context-support-6.2.2.jar spring-core-6.2.2.jar @@ -184,8 +219,10 @@ spring-jcl-6.2.2.jar spring-tx-6.2.2.jar stax2-api-4.2.jar staxon-1.2.jar +third-party-jackson-core-2.30.10.jar tika-core-2.9.2.jar txw2-4.0.5.jar +utils-2.30.10.jar vecmath-1.5.2.jar weld-servlet-shaded-5.1.3.Final.jar woodstox-core-5.4.0.jar diff --git a/xplan-webservices/xplan-webservices-workspaces/src/main/workspace/datasources/remoteows/mapserver.xml b/xplan-webservices/xplan-webservices-workspaces/src/main/workspace/datasources/remoteows/mapserver.xml index 858ed2deeebf4f6baf4313848a93689c6d878b09..5392dcf37d4d99fd4cfa66746181c2d18b252f33 100644 --- a/xplan-webservices/xplan-webservices-workspaces/src/main/workspace/datasources/remoteows/mapserver.xml +++ b/xplan-webservices/xplan-webservices-workspaces/src/main/workspace/datasources/remoteows/mapserver.xml @@ -20,7 +20,7 @@ --> <RemoteWMS xmlns="http://www.deegree.org/remoteows/wms"> <CapabilitiesDocumentLocation - location="http://localhost:8080/mapserver?request=GetCapabilities&service=WMS&version=1.1.1"/> + location="http://localhost:8080/xplan-mapserver?request=GetCapabilities&service=WMS&version=1.1.1"/> <ConnectionTimeout>10</ConnectionTimeout> <RequestTimeout>60</RequestTimeout> </RemoteWMS>