diff --git a/pom.xml b/pom.xml index 3789cd5609c70815a88d69255f8dbbeda33eac1c..4bec2f10aec39a7ae93e7e0a04b81962442652ef 100644 --- a/pom.xml +++ b/pom.xml @@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" - xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>de.ozgcloud.common</groupId> @@ -24,7 +24,7 @@ <testcontainers-keycloak.version>3.2.0</testcontainers-keycloak.version> <keycloak-admin-client.version>23.0.6</keycloak-admin-client.version> <mongock.version>5.4.0</mongock.version> - <lombok-mapstruct-binding.version>0.2.0</lombok-mapstruct-binding.version> + <lombok-mapstruct-binding.version>0.2.0</lombok-mapstruct-binding.version> <mapstruct-processor.version>1.5.5.Final</mapstruct-processor.version> </properties> @@ -69,9 +69,9 @@ <artifactId>spring-boot-starter-oauth2-resource-server</artifactId> </dependency> <dependency> - <groupId>org.springframework.boot</groupId> - <artifactId>spring-boot-configuration-processor</artifactId> - <optional>true</optional> + <groupId>org.springframework.boot</groupId> + <artifactId>spring-boot-configuration-processor</artifactId> + <optional>true</optional> </dependency> <!-- tools --> <dependency> @@ -84,6 +84,13 @@ <version>${mapstruct-processor.version}</version> </dependency> + <!-- native image --> + <dependency> + <groupId>org.graalvm.sdk</groupId> + <artifactId>graal-sdk</artifactId> + <version>24.0.0</version> + </dependency> + <!-- mongock --> <dependency> <groupId>io.mongock</groupId> @@ -245,22 +252,22 @@ <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> <configuration> - <image> - <name>${imageName}:${imageTag}</name> - <publish>${publishImage}</publish> - </image> - <docker> - <publishRegistry> - <username>${docker.publishRegistry.username}</username> - <password>${docker.publishRegistry.password}</password> - </publishRegistry> - </docker> - <excludes> - <exclude> - <groupId>org.projectlombok</groupId> - <artifactId>lombok</artifactId> - </exclude> - </excludes> + <image> + <name>${imageName}:${imageTag}</name> + <publish>${publishImage}</publish> + </image> + <docker> + <publishRegistry> + <username>${docker.publishRegistry.username}</username> + <password>${docker.publishRegistry.password}</password> + </publishRegistry> + </docker> + <excludes> + <exclude> + <groupId>org.projectlombok</groupId> + <artifactId>lombok</artifactId> + </exclude> + </excludes> </configuration> <executions> <execution> @@ -279,25 +286,25 @@ <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> - <configuration> - <annotationProcessorPaths> - <path> - <groupId>org.mapstruct</groupId> - <artifactId>mapstruct-processor</artifactId> - <version>${mapstruct-processor.version}</version> - </path> - <path> - <groupId>org.projectlombok</groupId> - <artifactId>lombok</artifactId> - <version>${lombok.version}</version> - </path> - <path> - <groupId>org.projectlombok</groupId> - <artifactId>lombok-mapstruct-binding</artifactId> - <version>${lombok-mapstruct-binding.version}</version> - </path> - </annotationProcessorPaths> - </configuration> + <configuration> + <annotationProcessorPaths> + <path> + <groupId>org.mapstruct</groupId> + <artifactId>mapstruct-processor</artifactId> + <version>${mapstruct-processor.version}</version> + </path> + <path> + <groupId>org.projectlombok</groupId> + <artifactId>lombok</artifactId> + <version>${lombok.version}</version> + </path> + <path> + <groupId>org.projectlombok</groupId> + <artifactId>lombok-mapstruct-binding</artifactId> + <version>${lombok-mapstruct-binding.version}</version> + </path> + </annotationProcessorPaths> + </configuration> </plugin> </plugins> </build> diff --git a/src/main/java/de/ozgcloud/admin/MigrationUnitRegistrationFeature.java b/src/main/java/de/ozgcloud/admin/MigrationUnitRegistrationFeature.java new file mode 100644 index 0000000000000000000000000000000000000000..23ff80637000adbec9c2f5f068b960572d414d53 --- /dev/null +++ b/src/main/java/de/ozgcloud/admin/MigrationUnitRegistrationFeature.java @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2024. Das Land Schleswig-Holstein vertreten durch das Ministerium für Energiewende, Klimaschutz, Umwelt und Natur + * Zentrales IT-Management + * + * Lizenziert unter der EUPL, Version 1.2 oder - sobald + * diese von der Europäischen Kommission genehmigt wurden - + * Folgeversionen der EUPL ("Lizenz"); + * Sie dürfen dieses Werk ausschließlich gemäß + * dieser Lizenz nutzen. + * Eine Kopie der Lizenz finden Sie hier: + * + * https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 + * + * Sofern nicht durch anwendbare Rechtsvorschriften + * gefordert oder in schriftlicher Form vereinbart, wird + * die unter der Lizenz verbreitete Software "so wie sie + * ist", OHNE JEGLICHE GEWÄHRLEISTUNG ODER BEDINGUNGEN - + * ausdrücklich oder stillschweigend - verbreitet. + * Die sprachspezifischen Genehmigungen und Beschränkungen + * unter der Lizenz sind dem Lizenztext zu entnehmen. + */ +package de.ozgcloud.admin; + +import org.graalvm.nativeimage.hosted.Feature; +import org.graalvm.nativeimage.hosted.RuntimeReflection; + +import de.ozgcloud.admin.migration.MigrationUnitList; + +public class MigrationUnitRegistrationFeature implements Feature { + + @Override + public void beforeAnalysis(BeforeAnalysisAccess access) { + MigrationUnitList.units.forEach(MigrationUnitRegistrationFeature::registerClass); + } + + private static void registerClass(Class<?> clazz) { + RuntimeReflection.register(clazz); + RuntimeReflection.register(clazz.getDeclaredConstructors()); + RuntimeReflection.register(clazz.getDeclaredMethods()); + } +} + diff --git a/src/main/java/de/ozgcloud/admin/migration/MigrationUnitList.java b/src/main/java/de/ozgcloud/admin/migration/MigrationUnitList.java new file mode 100644 index 0000000000000000000000000000000000000000..6497d8de1e6b27aa2f99fa2a7e2ca0ecd612c67e --- /dev/null +++ b/src/main/java/de/ozgcloud/admin/migration/MigrationUnitList.java @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2024. Das Land Schleswig-Holstein vertreten durch das Ministerium für Energiewende, Klimaschutz, Umwelt und Natur + * Zentrales IT-Management + * + * Lizenziert unter der EUPL, Version 1.2 oder - sobald + * diese von der Europäischen Kommission genehmigt wurden - + * Folgeversionen der EUPL ("Lizenz"); + * Sie dürfen dieses Werk ausschließlich gemäß + * dieser Lizenz nutzen. + * Eine Kopie der Lizenz finden Sie hier: + * + * https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 + * + * Sofern nicht durch anwendbare Rechtsvorschriften + * gefordert oder in schriftlicher Form vereinbart, wird + * die unter der Lizenz verbreitete Software "so wie sie + * ist", OHNE JEGLICHE GEWÄHRLEISTUNG ODER BEDINGUNGEN - + * ausdrücklich oder stillschweigend - verbreitet. + * Die sprachspezifischen Genehmigungen und Beschränkungen + * unter der Lizenz sind dem Lizenztext zu entnehmen. + */ +package de.ozgcloud.admin.migration; + +import java.util.List; + +public final class MigrationUnitList { + public static final List<Class<?>> units = List.of( + M001_CreateEmptyPostfachIfMissing.class + ); + + private MigrationUnitList() { + + } +} diff --git a/src/main/java/de/ozgcloud/admin/migration/MongockSuccessEventListener.java b/src/main/java/de/ozgcloud/admin/migration/MongockSuccessEventListener.java index 95a7f76ee988dc8f1e72b8db6341da77514e5b54..693fc7846738d9ad62690439a06954e3e7d6fa60 100644 --- a/src/main/java/de/ozgcloud/admin/migration/MongockSuccessEventListener.java +++ b/src/main/java/de/ozgcloud/admin/migration/MongockSuccessEventListener.java @@ -23,17 +23,18 @@ */ package de.ozgcloud.admin.migration; -import io.mongock.runner.spring.base.events.SpringMigrationSuccessEvent; -import lombok.extern.log4j.Log4j2; import org.springframework.context.ApplicationListener; import org.springframework.stereotype.Component; +import io.mongock.runner.spring.base.events.SpringMigrationSuccessEvent; +import lombok.extern.log4j.Log4j2; + @Log4j2 @Component public class MongockSuccessEventListener implements ApplicationListener<SpringMigrationSuccessEvent> { @Override public void onApplicationEvent(SpringMigrationSuccessEvent event) { - log.info("Mongock migration successfull", event.getMigrationResult()); + log.info("Mongock migration successful {}", event.getMigrationResult()); } -} \ No newline at end of file +} diff --git a/src/main/java/de/ozgcloud/admin/nativeimage/MigrationUnitAotProcessor.java b/src/main/java/de/ozgcloud/admin/nativeimage/MigrationUnitAotProcessor.java new file mode 100644 index 0000000000000000000000000000000000000000..9189eba8a07b0973262249675c8c52504f19fdd4 --- /dev/null +++ b/src/main/java/de/ozgcloud/admin/nativeimage/MigrationUnitAotProcessor.java @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2024. Das Land Schleswig-Holstein vertreten durch das Ministerium für Energiewende, Klimaschutz, Umwelt und Natur + * Zentrales IT-Management + * + * Lizenziert unter der EUPL, Version 1.2 oder - sobald + * diese von der Europäischen Kommission genehmigt wurden - + * Folgeversionen der EUPL ("Lizenz"); + * Sie dürfen dieses Werk ausschließlich gemäß + * dieser Lizenz nutzen. + * Eine Kopie der Lizenz finden Sie hier: + * + * https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 + * + * Sofern nicht durch anwendbare Rechtsvorschriften + * gefordert oder in schriftlicher Form vereinbart, wird + * die unter der Lizenz verbreitete Software "so wie sie + * ist", OHNE JEGLICHE GEWÄHRLEISTUNG ODER BEDINGUNGEN - + * ausdrücklich oder stillschweigend - verbreitet. + * Die sprachspezifischen Genehmigungen und Beschränkungen + * unter der Lizenz sind dem Lizenztext zu entnehmen. + */ +package de.ozgcloud.admin.nativeimage; + +import static org.springframework.aot.hint.MemberCategory.*; + +import java.util.Objects; +import java.util.Set; +import java.util.stream.Collectors; + +import org.springframework.aot.generate.GenerationContext; +import org.springframework.aot.hint.ReflectionHints; +import org.springframework.beans.factory.aot.BeanFactoryInitializationAotContribution; +import org.springframework.beans.factory.aot.BeanFactoryInitializationAotProcessor; +import org.springframework.beans.factory.aot.BeanFactoryInitializationCode; +import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; +import org.springframework.boot.autoconfigure.AutoConfigurationPackages; +import org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider; +import org.springframework.core.type.filter.AnnotationTypeFilter; +import org.springframework.util.ClassUtils; + +import io.mongock.api.annotations.ChangeUnit; +import io.mongock.runner.springboot.MongockSpringboot; +import io.mongock.utils.StringUtils; + +public class MigrationUnitAotProcessor implements BeanFactoryInitializationAotProcessor { + @Override + public BeanFactoryInitializationAotContribution processAheadOfTime(ConfigurableListableBeanFactory beanFactory) { + if (AutoConfigurationPackages.has(beanFactory)) { + var scanner = createScanner(); + Set<Class<?>> unitSet = AutoConfigurationPackages.get(beanFactory) + .stream() + .filter(StringUtils::hasText) + .flatMap(packageToScan -> scanner.findCandidateComponents(packageToScan).stream()) + .map(beanDefinition -> { + try { + return ClassUtils.forName(Objects.requireNonNull(beanDefinition.getBeanClassName()), + beanFactory.getBeanClassLoader()); + } catch (ClassNotFoundException e) { + throw new RuntimeException(e); + } + }).collect(Collectors.toSet()); + return (GenerationContext generationContext, BeanFactoryInitializationCode beanFactoryInitializationCode) -> + registerReflectiveHints(generationContext.getRuntimeHints().reflection(), unitSet); + } + return null; + } + + private ClassPathScanningCandidateComponentProvider createScanner() { + var scanner = new ClassPathScanningCandidateComponentProvider(false); + scanner.addIncludeFilter(new AnnotationTypeFilter(ChangeUnit.class)); + return scanner; + } + + private void registerReflectiveHints(ReflectionHints hints, Set<Class<?>> migrationUnits) { + for (var unit : migrationUnits) { + hints.registerType(unit, hint -> + hint.withMembers(INVOKE_DECLARED_METHODS, INVOKE_DECLARED_CONSTRUCTORS) + ); + } + hints.registerType(MongockSpringboot.RunnerSpringbootBuilderImpl.class, hint -> + hint.withMembers(INVOKE_DECLARED_METHODS, INVOKE_DECLARED_CONSTRUCTORS) + ); + } +}