diff --git a/archive-manager-interface/pom.xml b/archive-manager-interface/pom.xml index 45418c34646ed3129139c9450eb3e1aeb7ad2e67..b3d32c02ff8d18b6a41663d4c4d77e2a90438b1a 100644 --- a/archive-manager-interface/pom.xml +++ b/archive-manager-interface/pom.xml @@ -6,7 +6,7 @@ <parent> <groupId>de.ozgcloud.archive</groupId> <artifactId>archive-manager</artifactId> - <version>0.1.0-SNAPSHOT</version> + <version>0.2.0-SNAPSHOT</version> </parent> <artifactId>archive-manager-interface</artifactId> @@ -66,18 +66,6 @@ </executions> </plugin> - <plugin> - <groupId>org.apache.maven.plugins</groupId> - <artifactId>maven-source-plugin</artifactId> - <executions> - <execution> - <id>attach-sources</id> - <goals> - <goal>jar</goal> - </goals> - </execution> - </executions> - </plugin> <plugin> <groupId>io.github.floverfelt</groupId> <artifactId>find-and-replace-maven-plugin</artifactId> diff --git a/archive-manager-server/pom.xml b/archive-manager-server/pom.xml index 3dc366b19a4698cc0e15c97bd06be4de17feff37..0b6f5f4eabc7bf886484ec58c3f2e10c31d4bea8 100644 --- a/archive-manager-server/pom.xml +++ b/archive-manager-server/pom.xml @@ -7,7 +7,7 @@ <parent> <groupId>de.ozgcloud.archive</groupId> <artifactId>archive-manager</artifactId> - <version>0.1.0-SNAPSHOT</version> + <version>0.2.0-SNAPSHOT</version> </parent> <artifactId>archive-manager-server</artifactId> @@ -69,12 +69,6 @@ <groupId>de.ozgcloud.document</groupId> <artifactId>document-manager-interface</artifactId> </dependency> - <dependency> - <groupId>de.ozgcloud.api-lib</groupId> - <artifactId>api-lib-core</artifactId> - <type>test-jar</type> - <scope>test</scope> - </dependency> <dependency> <groupId>de.ozgcloud.xta</groupId> <artifactId>xta-client-lib</artifactId> diff --git a/archive-manager-server/src/main/java/de/ozgcloud/archive/ArchiveManagerConfiguration.java b/archive-manager-server/src/main/java/de/ozgcloud/archive/ArchiveManagerConfiguration.java index 79e21e02f53e0f993669341d6beab9319b21b1ec..247277431b87bdb7fa32e063f090e427db734f6a 100644 --- a/archive-manager-server/src/main/java/de/ozgcloud/archive/ArchiveManagerConfiguration.java +++ b/archive-manager-server/src/main/java/de/ozgcloud/archive/ArchiveManagerConfiguration.java @@ -1,15 +1,41 @@ package de.ozgcloud.archive; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import de.ozgcloud.apilib.client_attribute.OzgCloudClientAttributeService; +import de.ozgcloud.apilib.client_attribute.grpc.OzgCloudClientAttributeGrpcService; +import de.ozgcloud.apilib.client_attribute.grpc.OzgCloudClientAttributeMapper; +import de.ozgcloud.apilib.common.command.OzgCloudCommandService; +import de.ozgcloud.apilib.common.command.grpc.CommandMapper; +import de.ozgcloud.apilib.common.command.grpc.GrpcOzgCloudCommandService; +import de.ozgcloud.apilib.file.OzgCloudFileService; +import de.ozgcloud.apilib.file.grpc.GrpcOzgCloudFileService; +import de.ozgcloud.apilib.file.grpc.OzgCloudFileMapper; +import de.ozgcloud.apilib.user.GrpcOzgCloudUserProfileService; +import de.ozgcloud.apilib.user.OzgCloudUserProfileService; +import de.ozgcloud.apilib.user.UserProfileMapper; +import de.ozgcloud.archive.common.callcontext.CallContextProvider; +import de.ozgcloud.user.grpc.userprofile.UserProfileServiceGrpc.UserProfileServiceBlockingStub; +import de.ozgcloud.vorgang.grpc.binaryFile.BinaryFileServiceGrpc.BinaryFileServiceBlockingStub; +import de.ozgcloud.vorgang.grpc.binaryFile.BinaryFileServiceGrpc.BinaryFileServiceStub; +import de.ozgcloud.vorgang.grpc.clientAttribute.ClientAttributeServiceGrpc.ClientAttributeServiceBlockingStub; +import de.ozgcloud.vorgang.grpc.command.CommandServiceGrpc.CommandServiceBlockingStub; +import lombok.RequiredArgsConstructor; +import net.devh.boot.grpc.client.inject.GrpcClient; + @Configuration -public class ArchiveManagerConfiguration { // NOSONAR +@RequiredArgsConstructor +public class ArchiveManagerConfiguration { + public static final String VORGANG_SERVICE_NAME = "archive_VorgangService"; public static final String VORGANG_REMOTE_MANAGER_SERVICE_NAME = "archive_VorgangRemoteService"; public static final String VORGANG_WITH_EINGANG_MAPPER_NAME = "archive_VorgangWithEingangMapper"; public static final String CURRENT_USER_SERVICE_NAME = "archive_CurrentUserService"; public static final String DOCUMENT_MAPPER_NAME = "archive_DocumentMapper"; + public static final String DOCUMENT_REMOTE_SERVICE_NAME = "archive_DocumentRemoteService"; public static final String USER_SERVICE_NAME = "archive_UserService"; public static final String USER_PROFILE_MAPPER_NAME = "archive_UserProfileMapper"; @@ -18,6 +44,7 @@ public class ArchiveManagerConfiguration { // NOSONAR public static final String COMMAND_SERVICE_NAME = "archive_CommandService"; public static final String COMMAND_REMOTE_SERVICE_NAME = "archive_CommandRemoteService"; public static final String COMMAND_MAPPER_NAME = "archive_CommandMapper"; + public static final String OZGCLOUD_COMMAND_SERVICE_NAME = "archive_OzgCloudCommandService"; public static final String BINARY_FILE_SERVICE_NAME = "archive_BinaryFileService"; public static final String BINARY_FILE_REMOTE_SERVICE_NAME = "archive_BinaryFileRemoteService"; @@ -28,6 +55,59 @@ public class ArchiveManagerConfiguration { // NOSONAR public static final String BESCHEID_REMOTE_SERVICE_NAME = "archive_BescheidRemoteService"; public static final String BESCHEID_MAPPER_NAME = "archive_BescheidMapper"; - public static final String OZGCLOUD_CALL_CONTEXT_PROVIDER_NAME = "archive_CallContextProvider"; + public static final String CALL_CONTEXT_PROVIDER_NAME = "archive_CallContextProvider"; + public static final String CALL_CONTEXT_MAPPER_NAME = "archive_CallContextMapper"; + + public static final String CLIENT_ATTRIBUTE_SERVICE_NAME = "archive_ClientAttributeService"; + public static final String OZGCLOUD_CLIENT_ATTRIBUTE_SERVICE_NAME = "archive_OzgCloudClientAttributeService"; + + public static final String KOMMENTAR_SERVICE_NAME = "archive_KommentarService"; + public static final String KOMMENTAR_REMOTE_SERVICE_NAME = "archive_KommentarRemoteService"; + + public static final String CALL_CONTEXT_SERVER_INTERCEPTOR_NAME = "archive_CallContextGrpcServerInterceptor"; + + public static final String GRPC_VORGANG_MANAGER_CLIENT_NAME = "vorgang-manager"; + public static final String GRPC_COMMAND_MANAGER_CLIENT_NAME = "command-manager"; + public static final String GRPC_FILE_MANAGER_CLIENT_NAME = "file-manager"; + public static final String GRPC_USER_MANAGER_CLIENT_NAME = "user-manager"; + + @GrpcClient(GRPC_VORGANG_MANAGER_CLIENT_NAME) + private final ClientAttributeServiceBlockingStub clientAttributeServiceBlockingStub; + + @GrpcClient(GRPC_COMMAND_MANAGER_CLIENT_NAME) + private final CommandServiceBlockingStub commandServiceStub; + + @GrpcClient(GRPC_USER_MANAGER_CLIENT_NAME) + private final UserProfileServiceBlockingStub userProfileServiceBlockingStub; + + @GrpcClient(GRPC_FILE_MANAGER_CLIENT_NAME) + private final BinaryFileServiceBlockingStub binaryFileServiceBlockingStub; + + @GrpcClient(GRPC_FILE_MANAGER_CLIENT_NAME) + private final BinaryFileServiceStub binaryFileServiceStub; + + @Bean(ArchiveManagerConfiguration.OZGCLOUD_FILE_SERVICE_NAME) // NOSONAR + OzgCloudFileService ozgCloudFileService(OzgCloudFileMapper mapper, + @Qualifier(CALL_CONTEXT_PROVIDER_NAME) CallContextProvider callContextProvider) { + return new GrpcOzgCloudFileService(binaryFileServiceBlockingStub, binaryFileServiceStub, callContextProvider, mapper); + } + + @Bean(ArchiveManagerConfiguration.OZGCLOUD_USER_PROFILE_SERVICE_NAME) // NOSONAR + OzgCloudUserProfileService grpcOzgCloudUserProfileService(UserProfileMapper userProfileMapper, + @Qualifier(CALL_CONTEXT_PROVIDER_NAME) CallContextProvider callContextProvider) { + return new GrpcOzgCloudUserProfileService(userProfileServiceBlockingStub, userProfileMapper, callContextProvider); + } + + @Bean(OZGCLOUD_CLIENT_ATTRIBUTE_SERVICE_NAME) // NOSONAR + OzgCloudClientAttributeService ozgCloudAttributesService(OzgCloudClientAttributeMapper mapper, + @Qualifier(CALL_CONTEXT_PROVIDER_NAME) CallContextProvider callContextProvider) { + return new OzgCloudClientAttributeGrpcService(clientAttributeServiceBlockingStub, mapper, callContextProvider); + } + @Bean(OZGCLOUD_COMMAND_SERVICE_NAME) // NOSONAR + OzgCloudCommandService ozgCloudCommandService(CommandMapper commandMapper, + @Qualifier(CALL_CONTEXT_PROVIDER_NAME) CallContextProvider callContextProvider) { + return new GrpcOzgCloudCommandService(commandServiceStub, commandMapper, callContextProvider, + GrpcOzgCloudCommandService.DEFAULT_COMMAND_REQUEST_THRESHOLD_MILLIS); + } } diff --git a/archive-manager-server/src/main/java/de/ozgcloud/archive/OzgcloudConfiguration.java b/archive-manager-server/src/main/java/de/ozgcloud/archive/OzgcloudConfiguration.java deleted file mode 100644 index 0311d0420c079af88e3f04daa8e831741f7d359b..0000000000000000000000000000000000000000 --- a/archive-manager-server/src/main/java/de/ozgcloud/archive/OzgcloudConfiguration.java +++ /dev/null @@ -1,46 +0,0 @@ -package de.ozgcloud.archive; - -import org.springframework.beans.factory.annotation.Qualifier; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; - -import de.ozgcloud.apilib.common.callcontext.OzgCloudCallContextProvider; -import de.ozgcloud.apilib.file.OzgCloudFileService; -import de.ozgcloud.apilib.file.grpc.GrpcOzgCloudFileService; -import de.ozgcloud.apilib.file.grpc.OzgCloudFileMapper; -import de.ozgcloud.apilib.user.GrpcOzgCloudUserProfileService; -import de.ozgcloud.apilib.user.OzgCloudUserProfileService; -import de.ozgcloud.apilib.user.UserProfileMapper; -import de.ozgcloud.archive.common.GrpcUtil; -import de.ozgcloud.user.grpc.userprofile.UserProfileServiceGrpc.UserProfileServiceBlockingStub; -import de.ozgcloud.vorgang.grpc.binaryFile.BinaryFileServiceGrpc.BinaryFileServiceBlockingStub; -import de.ozgcloud.vorgang.grpc.binaryFile.BinaryFileServiceGrpc.BinaryFileServiceStub; -import net.devh.boot.grpc.client.inject.GrpcClient; - -@Configuration -class OzgcloudConfiguration { - - @GrpcClient(GrpcUtil.USER_MANAGER_GRPC_CLIENT) - private UserProfileServiceBlockingStub userProfileServiceBlockingStub; - - @GrpcClient(GrpcUtil.FILE_MANAGER_GRPC_CLIENT) - private BinaryFileServiceBlockingStub binaryFileServiceBlockingStub; - - @GrpcClient(GrpcUtil.FILE_MANAGER_GRPC_CLIENT) - private BinaryFileServiceStub binaryFileServiceStub; - - @Bean(ArchiveManagerConfiguration.OZGCLOUD_FILE_SERVICE_NAME) - OzgCloudFileService ozgCloudFileService( - @Qualifier(ArchiveManagerConfiguration.OZGCLOUD_CALL_CONTEXT_PROVIDER_NAME) OzgCloudCallContextProvider contextProvider, - OzgCloudFileMapper mapper) { - - return new GrpcOzgCloudFileService(binaryFileServiceBlockingStub, binaryFileServiceStub, contextProvider, mapper); - } - - @Bean(ArchiveManagerConfiguration.OZGCLOUD_USER_PROFILE_SERVICE_NAME) // NOSONAR - OzgCloudUserProfileService grpcOzgCloudUserProfileService( - @Qualifier(ArchiveManagerConfiguration.OZGCLOUD_CALL_CONTEXT_PROVIDER_NAME) OzgCloudCallContextProvider callContextProvider, - UserProfileMapper userProfileMapper) { - return new GrpcOzgCloudUserProfileService(userProfileServiceBlockingStub, userProfileMapper, callContextProvider); - } -} diff --git a/archive-manager-server/src/main/java/de/ozgcloud/archive/XtaConfiguration.java b/archive-manager-server/src/main/java/de/ozgcloud/archive/XtaConfiguration.java deleted file mode 100644 index 2c75525bc1cb91a82f24613875d96c9c3c86d16e..0000000000000000000000000000000000000000 --- a/archive-manager-server/src/main/java/de/ozgcloud/archive/XtaConfiguration.java +++ /dev/null @@ -1,51 +0,0 @@ -package de.ozgcloud.archive; - -import java.io.IOException; - -import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; - -import de.ozgcloud.archive.XtaProperties.XtaClientKeyStore; -import de.ozgcloud.common.errorhandling.TechnicalException; -import de.ozgcloud.xta.client.XtaClient; -import de.ozgcloud.xta.client.config.XtaClientConfig; -import de.ozgcloud.xta.client.config.XtaClientConfig.KeyStore; -import de.ozgcloud.xta.client.exception.XtaClientInitializationException; - -@Configuration -class XtaConfiguration { - - @Bean - @ConditionalOnProperty(XtaProperties.XTA_PROPERTIES_PREFIX) - XtaClient xtaClient(XtaProperties xtaProperties) { - try { - return XtaClient.from(buildXtaClientConfig(xtaProperties)); - } catch (XtaClientInitializationException e) { - throw new TechnicalException("Error on initializing Xta client.", e); - } - } - - XtaClientConfig buildXtaClientConfig(XtaProperties xtaProperties) { - try { - return XtaClientConfig.builder() - .sendServiceUrl(xtaProperties.getSendServiceUrl()) - .managementServiceUrl(xtaProperties.getManagementServiceUrl()) - .msgBoxServiceUrl(xtaProperties.getMsgBoxServiceUrl()) - .clientCertKeystore(buildClientCertKeystore(xtaProperties.getKeyStore())) - .maxListItems(xtaProperties.getMaxListItems()) - .clientIdentifiers(xtaProperties.getClientIdentifiers()) - .build(); - } catch (IOException e) { - throw new TechnicalException("Error on reading Xta client certificate.", e); - } - } - - private KeyStore buildClientCertKeystore(XtaClientKeyStore clientCert) throws IOException { - return XtaClientConfig.KeyStore.builder() - .content(clientCert.getFile().getContentAsByteArray()) - .type(clientCert.getType()) - .password(clientCert.getPassword()) - .build(); - } -} diff --git a/archive-manager-server/src/main/java/de/ozgcloud/archive/attributes/ClientAttributeService.java b/archive-manager-server/src/main/java/de/ozgcloud/archive/attributes/ClientAttributeService.java new file mode 100644 index 0000000000000000000000000000000000000000..21d24f804eb7d430b399243e9af5baaa8affecb8 --- /dev/null +++ b/archive-manager-server/src/main/java/de/ozgcloud/archive/attributes/ClientAttributeService.java @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2024 Das Land Schleswig-Holstein vertreten durch den + * Ministerpräsidenten des Landes Schleswig-Holstein + * Staatskanzlei + * Abteilung Digitalisierung und zentrales IT-Management der Landesregierung + * + * 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.archive.attributes; + +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.stereotype.Service; + +import de.ozgcloud.apilib.client_attribute.OzgCloudAccessPermission; +import de.ozgcloud.apilib.client_attribute.OzgCloudBooleanClientAttribute; +import de.ozgcloud.apilib.client_attribute.OzgCloudClientAttributeService; +import de.ozgcloud.apilib.vorgang.OzgCloudVorgangIdMapper; +import de.ozgcloud.archive.ArchiveManagerConfiguration; +import de.ozgcloud.archive.common.callcontext.CallContextUser; +import lombok.RequiredArgsConstructor; + +@Service(ArchiveManagerConfiguration.CLIENT_ATTRIBUTE_SERVICE_NAME) // NOSONAR +@RequiredArgsConstructor +public class ClientAttributeService { + + public static final String ATTRIBUTE_NAME_ANTRAG_ARCHIVING = "ARCHIVING"; + + @Qualifier(ArchiveManagerConfiguration.OZGCLOUD_CLIENT_ATTRIBUTE_SERVICE_NAME) // NOSONAR + private final OzgCloudClientAttributeService ozgCloudAttributesService; + + private final OzgCloudVorgangIdMapper vorgangIdMapper; + + public void setVorgangArchiving(String vorgangId) { + ozgCloudAttributesService.setClientAttribute(buildBooleanClientAttribute(true), vorgangIdMapper.fromString(vorgangId)); + } + + OzgCloudBooleanClientAttribute buildBooleanClientAttribute(boolean isArchiving) { + return OzgCloudBooleanClientAttribute.builder() + .clientName(CallContextUser.ARCHIVE_MANAGER_CLIENT_NAME) + .access(OzgCloudAccessPermission.READ_ONLY) + .attributeName(ATTRIBUTE_NAME_ANTRAG_ARCHIVING) + .value(isArchiving) + .build(); + } + +} diff --git a/archive-manager-server/src/main/java/de/ozgcloud/archive/bescheid/BescheidRemoteService.java b/archive-manager-server/src/main/java/de/ozgcloud/archive/bescheid/BescheidRemoteService.java index eda3d0ccd43ec3a5c9a419f183af1a13015e08e7..7b1e5095cc9d5f4f4afc72be229788472c3817c8 100644 --- a/archive-manager-server/src/main/java/de/ozgcloud/archive/bescheid/BescheidRemoteService.java +++ b/archive-manager-server/src/main/java/de/ozgcloud/archive/bescheid/BescheidRemoteService.java @@ -2,29 +2,27 @@ package de.ozgcloud.archive.bescheid; import java.util.stream.Stream; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.stereotype.Service; import de.ozgcloud.apilib.common.callcontext.OzgCloudCallContextAttachingInterceptor; import de.ozgcloud.apilib.common.callcontext.OzgCloudCallContextProvider; import de.ozgcloud.archive.ArchiveManagerConfiguration; -import de.ozgcloud.archive.common.GrpcUtil; import de.ozgcloud.document.bescheid.BescheidServiceGrpc.BescheidServiceBlockingStub; import de.ozgcloud.document.bescheid.GrpcGetAllBescheidRequest; +import lombok.RequiredArgsConstructor; import net.devh.boot.grpc.client.inject.GrpcClient; @Service(ArchiveManagerConfiguration.BESCHEID_REMOTE_SERVICE_NAME) // NOSONAR +@RequiredArgsConstructor class BescheidRemoteService { - @GrpcClient(GrpcUtil.VORGANG_MANAGER_GRPC_CLIENT) - private BescheidServiceBlockingStub grpcService; - @Autowired - @Qualifier(ArchiveManagerConfiguration.OZGCLOUD_CALL_CONTEXT_PROVIDER_NAME) - private OzgCloudCallContextProvider contextProvider; - @Autowired + @GrpcClient(ArchiveManagerConfiguration.GRPC_VORGANG_MANAGER_CLIENT_NAME) + private final BescheidServiceBlockingStub grpcService; + @Qualifier(ArchiveManagerConfiguration.CALL_CONTEXT_PROVIDER_NAME) // NOSONAR + private final OzgCloudCallContextProvider contextProvider; @Qualifier(ArchiveManagerConfiguration.BESCHEID_MAPPER_NAME) // NOSONAR - private BescheidMapper bescheidMapper; + private final BescheidMapper bescheidMapper; public Stream<Bescheid> findByVorgangId(String vorgangId) { var request = buildGetAllBescheidRequest(vorgangId); diff --git a/archive-manager-server/src/main/java/de/ozgcloud/archive/bescheid/DocumentRemoteService.java b/archive-manager-server/src/main/java/de/ozgcloud/archive/bescheid/DocumentRemoteService.java index 1eead2e35a5cef9783cf6f9bbb465179a619e001..5428fdda81422b96ac5ee1d0490e2e7773367785 100644 --- a/archive-manager-server/src/main/java/de/ozgcloud/archive/bescheid/DocumentRemoteService.java +++ b/archive-manager-server/src/main/java/de/ozgcloud/archive/bescheid/DocumentRemoteService.java @@ -1,29 +1,27 @@ package de.ozgcloud.archive.bescheid; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.stereotype.Service; import de.ozgcloud.apilib.common.callcontext.OzgCloudCallContextAttachingInterceptor; import de.ozgcloud.apilib.common.callcontext.OzgCloudCallContextProvider; import de.ozgcloud.archive.ArchiveManagerConfiguration; -import de.ozgcloud.archive.common.GrpcUtil; import de.ozgcloud.common.binaryfile.FileId; import de.ozgcloud.document.DocumentServiceGrpc.DocumentServiceBlockingStub; import de.ozgcloud.document.GrpcGetDocumentRequest; +import lombok.RequiredArgsConstructor; import net.devh.boot.grpc.client.inject.GrpcClient; -@Service +@Service(ArchiveManagerConfiguration.DOCUMENT_REMOTE_SERVICE_NAME) // NOSONAR +@RequiredArgsConstructor class DocumentRemoteService { - @GrpcClient(GrpcUtil.VORGANG_MANAGER_GRPC_CLIENT) - private DocumentServiceBlockingStub grpcService; - @Autowired + @GrpcClient(ArchiveManagerConfiguration.GRPC_VORGANG_MANAGER_CLIENT_NAME) // NOSONAR + private final DocumentServiceBlockingStub grpcService; @Qualifier(ArchiveManagerConfiguration.DOCUMENT_MAPPER_NAME) // NOSONAR - private DocumentMapper documentMapper; - @Autowired - @Qualifier(ArchiveManagerConfiguration.OZGCLOUD_CALL_CONTEXT_PROVIDER_NAME) - private OzgCloudCallContextProvider contextProvider; + private final DocumentMapper documentMapper; + @Qualifier(ArchiveManagerConfiguration.CALL_CONTEXT_PROVIDER_NAME) // NOSONAR + private final OzgCloudCallContextProvider contextProvider; public FileId getDocument(String documentId) { var response = getGrpcServiceWithInterceptor().getDocument(GrpcGetDocumentRequest.newBuilder().setId(documentId).build()); diff --git a/archive-manager-server/src/main/java/de/ozgcloud/archive/bescheid/ExportBescheidService.java b/archive-manager-server/src/main/java/de/ozgcloud/archive/bescheid/ExportBescheidService.java index 7fe61a04059da950ac3cd7950cc0f8854ed4dc3b..0a120e71f6e69af9060f471df95714e3713ec328 100644 --- a/archive-manager-server/src/main/java/de/ozgcloud/archive/bescheid/ExportBescheidService.java +++ b/archive-manager-server/src/main/java/de/ozgcloud/archive/bescheid/ExportBescheidService.java @@ -23,6 +23,7 @@ public class ExportBescheidService { @Qualifier(ArchiveManagerConfiguration.BINARY_FILE_SERVICE_NAME) // NOSONAR private final BinaryFileService binaryFileService; + @Qualifier(ArchiveManagerConfiguration.DOCUMENT_REMOTE_SERVICE_NAME) // NOSONAR private final DocumentRemoteService documentRemoteService; @Qualifier(ArchiveManagerConfiguration.USER_SERVICE_NAME) // NOSONAR diff --git a/archive-manager-server/src/main/java/de/ozgcloud/archive/common/GrpcUtil.java b/archive-manager-server/src/main/java/de/ozgcloud/archive/common/GrpcUtil.java deleted file mode 100644 index c7ecb0d7e72af32754fcb642ed011d36c58ab42c..0000000000000000000000000000000000000000 --- a/archive-manager-server/src/main/java/de/ozgcloud/archive/common/GrpcUtil.java +++ /dev/null @@ -1,13 +0,0 @@ -package de.ozgcloud.archive.common; - -import lombok.AccessLevel; -import lombok.NoArgsConstructor; - -@NoArgsConstructor(access = AccessLevel.PRIVATE) -public class GrpcUtil { - - public static final String VORGANG_MANAGER_GRPC_CLIENT = "vorgang-manager"; - public static final String FILE_MANAGER_GRPC_CLIENT = "file-manager"; - public static final String USER_MANAGER_GRPC_CLIENT = "user-manager"; - -} diff --git a/archive-manager-server/src/main/java/de/ozgcloud/archive/common/binaryfile/BinaryFileRemoteService.java b/archive-manager-server/src/main/java/de/ozgcloud/archive/common/binaryfile/BinaryFileRemoteService.java index 81d450f5df26ba8bb5eb6f02e0e49a5477929bd1..733788b6492552491eb97d7ad78a1486d813c697 100644 --- a/archive-manager-server/src/main/java/de/ozgcloud/archive/common/binaryfile/BinaryFileRemoteService.java +++ b/archive-manager-server/src/main/java/de/ozgcloud/archive/common/binaryfile/BinaryFileRemoteService.java @@ -4,7 +4,6 @@ import java.io.OutputStream; import java.util.List; import java.util.stream.Stream; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.stereotype.Service; @@ -12,32 +11,32 @@ import de.ozgcloud.apilib.common.callcontext.OzgCloudCallContextAttachingInterce import de.ozgcloud.apilib.common.callcontext.OzgCloudCallContextProvider; import de.ozgcloud.apilib.file.OzgCloudFileService; import de.ozgcloud.archive.ArchiveManagerConfiguration; -import de.ozgcloud.archive.common.GrpcUtil; import de.ozgcloud.archive.file.OzgFile; import de.ozgcloud.archive.file.OzgFileMapper; import de.ozgcloud.common.binaryfile.FileId; import de.ozgcloud.vorgang.grpc.binaryFile.BinaryFileServiceGrpc.BinaryFileServiceBlockingStub; import de.ozgcloud.vorgang.grpc.binaryFile.GrpcBinaryFilesRequest; import de.ozgcloud.vorgang.grpc.binaryFile.GrpcFindFilesResponse; +import lombok.RequiredArgsConstructor; import net.devh.boot.grpc.client.inject.GrpcClient; @Service(ArchiveManagerConfiguration.BINARY_FILE_REMOTE_SERVICE_NAME) // NOSONAR +@RequiredArgsConstructor class BinaryFileRemoteService { - @GrpcClient(GrpcUtil.VORGANG_MANAGER_GRPC_CLIENT) - private BinaryFileServiceBlockingStub grpcService; - @Autowired - @Qualifier(ArchiveManagerConfiguration.OZGCLOUD_FILE_SERVICE_NAME) - private OzgCloudFileService ozgCloudFileService; - @Autowired - private OzgFileMapper ozgFileMapper; - @Autowired - @Qualifier(ArchiveManagerConfiguration.OZGCLOUD_CALL_CONTEXT_PROVIDER_NAME) - private OzgCloudCallContextProvider contextProvider; - - @Autowired + @GrpcClient(ArchiveManagerConfiguration.GRPC_VORGANG_MANAGER_CLIENT_NAME) // NOSONAR + private final BinaryFileServiceBlockingStub grpcService; + + @Qualifier(ArchiveManagerConfiguration.OZGCLOUD_FILE_SERVICE_NAME) // NOSONAR + private final OzgCloudFileService ozgCloudFileService; + + private final OzgFileMapper ozgFileMapper; + + @Qualifier(ArchiveManagerConfiguration.CALL_CONTEXT_PROVIDER_NAME) // NOSONAR + private final OzgCloudCallContextProvider contextProvider; + @Qualifier(ArchiveManagerConfiguration.FILE_ID_MAPPER_NAME) // NOSONAR - private FileIdMapper fileIdMapper; + private final FileIdMapper fileIdMapper; public Stream<OzgFile> getFiles(List<FileId> fileIds) { var response = getGrpcServiceWithInterceptor().findBinaryFilesMetaData(buildBinaryFilesRequest(fileIds)); diff --git a/archive-manager-server/src/main/java/de/ozgcloud/archive/common/callcontext/ArchiveCallContext.java b/archive-manager-server/src/main/java/de/ozgcloud/archive/common/callcontext/ArchiveCallContext.java deleted file mode 100644 index 5af38120e0ee69c9359462afc7b3b175a8dad594..0000000000000000000000000000000000000000 --- a/archive-manager-server/src/main/java/de/ozgcloud/archive/common/callcontext/ArchiveCallContext.java +++ /dev/null @@ -1,26 +0,0 @@ -package de.ozgcloud.archive.common.callcontext; - -import java.util.Collection; -import java.util.UUID; - -import lombok.Builder; -import lombok.Getter; -import lombok.Singular; - -@Builder -@Getter -public class ArchiveCallContext { - - public static final String CLIENT_NAME = "OzgCloud_ArchiveManager"; - - @Builder.Default - private String clientName = CLIENT_NAME; - private String userId; - - @Builder.Default - private String requestId = UUID.randomUUID().toString(); - @Builder.Default - private boolean accessLimited = false; - @Singular - private Collection<String> accessLimitedToOrgaIds; -} diff --git a/archive-manager-server/src/main/java/de/ozgcloud/archive/common/callcontext/ArchiveCallContextMapper.java b/archive-manager-server/src/main/java/de/ozgcloud/archive/common/callcontext/ArchiveCallContextMapper.java deleted file mode 100644 index 43c2125c9914a943cf5a2ceba8dcc6558658e33c..0000000000000000000000000000000000000000 --- a/archive-manager-server/src/main/java/de/ozgcloud/archive/common/callcontext/ArchiveCallContextMapper.java +++ /dev/null @@ -1,15 +0,0 @@ -package de.ozgcloud.archive.common.callcontext; - -import org.mapstruct.Mapper; -import org.mapstruct.Mapping; - -import de.ozgcloud.apilib.common.callcontext.CallContext; -import de.ozgcloud.archive.common.user.OzgCloudUserIdMapper; - -@Mapper(uses = OzgCloudUserIdMapper.class) -public interface ArchiveCallContextMapper { - - @Mapping(target = "accessLimitedToOrgaId", ignore = true) - CallContext toOzgCloudCallContext(ArchiveCallContext archiveCallContext); - -} diff --git a/archive-manager-server/src/main/java/de/ozgcloud/archive/common/callcontext/CallContextAuthenticationToken.java b/archive-manager-server/src/main/java/de/ozgcloud/archive/common/callcontext/CallContextAuthenticationToken.java index d9709a8aa4f6f0953a5c19611374accaa56564c7..156357c600baab2fe7d0034cdb77729a24fd709e 100644 --- a/archive-manager-server/src/main/java/de/ozgcloud/archive/common/callcontext/CallContextAuthenticationToken.java +++ b/archive-manager-server/src/main/java/de/ozgcloud/archive/common/callcontext/CallContextAuthenticationToken.java @@ -31,7 +31,9 @@ import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.authority.SimpleGrantedAuthority; import lombok.EqualsAndHashCode; +import lombok.Getter; +@Getter @EqualsAndHashCode(callSuper = true) public class CallContextAuthenticationToken extends AbstractAuthenticationToken { @@ -42,7 +44,7 @@ public class CallContextAuthenticationToken extends AbstractAuthenticationToken } private CallContextAuthenticationToken(CallContextUser user) { - super(user.getOrganisatorischeEinheitenIds().stream().map(SimpleGrantedAuthority::new).collect(Collectors.toSet())); + super(user.getAccessLimitedToOrgaIds().stream().map(SimpleGrantedAuthority::new).collect(Collectors.toSet())); this.user = user; super.setAuthenticated(true); } @@ -54,11 +56,11 @@ public class CallContextAuthenticationToken extends AbstractAuthenticationToken @Override public Object getPrincipal() { - return user; + return getUser(); } @Override public Collection<GrantedAuthority> getAuthorities() { - return user.getOrganisatorischeEinheitenIds().stream().map(SimpleGrantedAuthority::new).collect(Collectors.toUnmodifiableSet()); + return user.getAccessLimitedToOrgaIds().stream().map(SimpleGrantedAuthority::new).collect(Collectors.toUnmodifiableSet()); } } diff --git a/archive-manager-server/src/main/java/de/ozgcloud/archive/common/callcontext/CallContextConfiguration.java b/archive-manager-server/src/main/java/de/ozgcloud/archive/common/callcontext/CallContextConfiguration.java deleted file mode 100644 index ffaabe7c2236d88f41f561056f620ac9306817cb..0000000000000000000000000000000000000000 --- a/archive-manager-server/src/main/java/de/ozgcloud/archive/common/callcontext/CallContextConfiguration.java +++ /dev/null @@ -1,16 +0,0 @@ -package de.ozgcloud.archive.common.callcontext; - -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; - -import de.ozgcloud.apilib.common.callcontext.OzgCloudCallContextProvider; -import de.ozgcloud.archive.ArchiveManagerConfiguration; - -@Configuration -public class CallContextConfiguration { - - @Bean(ArchiveManagerConfiguration.OZGCLOUD_CALL_CONTEXT_PROVIDER_NAME) - OzgCloudCallContextProvider callContextProvider(ArchiveCallContextMapper mapper) { - return new CallContextProvider(mapper, CallContextInterceptor.CONTEXT_KEY_CALL_CONTEXT::get); - } -} diff --git a/archive-manager-server/src/main/java/de/ozgcloud/archive/common/callcontext/CallContextGrpcServerInterceptor.java b/archive-manager-server/src/main/java/de/ozgcloud/archive/common/callcontext/CallContextGrpcServerInterceptor.java new file mode 100644 index 0000000000000000000000000000000000000000..3ea2660d6c5ca7cee1400f01a572da5ab9cb87a3 --- /dev/null +++ b/archive-manager-server/src/main/java/de/ozgcloud/archive/common/callcontext/CallContextGrpcServerInterceptor.java @@ -0,0 +1,86 @@ +package de.ozgcloud.archive.common.callcontext; + +import java.util.UUID; + +import org.apache.logging.log4j.CloseableThreadContext; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.security.core.context.SecurityContext; +import org.springframework.stereotype.Component; + +import de.ozgcloud.archive.ArchiveManagerConfiguration; +import de.ozgcloud.common.grpc.GrpcUtil; +import io.grpc.ForwardingServerCallListener; +import io.grpc.Metadata; +import io.grpc.ServerCall; +import io.grpc.ServerCall.Listener; +import io.grpc.ServerCallHandler; +import io.grpc.ServerInterceptor; +import lombok.RequiredArgsConstructor; + +@Component(ArchiveManagerConfiguration.CALL_CONTEXT_SERVER_INTERCEPTOR_NAME) // NOSONAR +@RequiredArgsConstructor +public class CallContextGrpcServerInterceptor implements ServerInterceptor { + + @Qualifier(ArchiveManagerConfiguration.CURRENT_USER_SERVICE_NAME) // NOSONAR + private final CurrentUserService currentUserService; + @Qualifier(ArchiveManagerConfiguration.CALL_CONTEXT_MAPPER_NAME) // NOSONAR + private final CallContextMapper callContextMapper; + + @Override + public <A, B> Listener<A> interceptCall(ServerCall<A, B> call, Metadata headers, ServerCallHandler<A, B> next) { + return new LogContextSettingListener<>(next.startCall(call, headers), headers); + } + + class LogContextSettingListener<A> extends ForwardingServerCallListener.SimpleForwardingServerCallListener<A> { + + private final String requestId; + private final Metadata headers; + + public LogContextSettingListener(ServerCall.Listener<A> delegate, Metadata headers) { + super(delegate); + this.headers = headers; + this.requestId = getRequestId(headers); + } + + String getRequestId(Metadata headers) { + return GrpcUtil.getRequestId(headers).orElseGet(() -> UUID.randomUUID().toString()); + } + + @Override + public void onMessage(A message) { + doSurroundOn(() -> super.onMessage(message)); + } + + @Override + public void onHalfClose() { + doSurroundOn(super::onHalfClose); + } + + @Override + public void onCancel() { + doSurroundOn(super::onCancel); + } + + @Override + public void onComplete() { + doSurroundOn(super::onComplete); + } + + @Override + public void onReady() { + doSurroundOn(super::onReady); + } + + void doSurroundOn(Runnable runnable) { + SecurityContext securityContext = null; + try (var ctc = CloseableThreadContext.put(GrpcUtil.KEY_REQUEST_ID, requestId)) { + securityContext = currentUserService.startAndReturnPreviousSecurityContext(callContextMapper.toCallContextUser(headers, requestId)); + runnable.run(); + } finally { + currentUserService.resetSecurityContext(securityContext); + } + } + + } + +} diff --git a/archive-manager-server/src/main/java/de/ozgcloud/archive/common/callcontext/CallContextInterceptor.java b/archive-manager-server/src/main/java/de/ozgcloud/archive/common/callcontext/CallContextInterceptor.java deleted file mode 100644 index f2736787df9f53f3bb11ced8b6af76b9d2d7d24e..0000000000000000000000000000000000000000 --- a/archive-manager-server/src/main/java/de/ozgcloud/archive/common/callcontext/CallContextInterceptor.java +++ /dev/null @@ -1,40 +0,0 @@ -package de.ozgcloud.archive.common.callcontext; - -import static de.ozgcloud.common.grpc.GrpcUtil.*; - -import org.apache.commons.lang3.StringUtils; -import org.springframework.stereotype.Component; - -import io.grpc.Context; -import io.grpc.Contexts; -import io.grpc.Metadata; -import io.grpc.ServerCall; -import io.grpc.ServerCall.Listener; -import io.grpc.ServerCallHandler; -import io.grpc.ServerInterceptor; -import lombok.RequiredArgsConstructor; - -@Component -@RequiredArgsConstructor -public class CallContextInterceptor implements ServerInterceptor { - - static final String KEY_USER_ID = "USER_ID-bin"; - static final String KEY_ACCESS_LIMITED = "ACCESS_LIMITED-bin"; - static final String KEY_ACCESS_LIMITED_ORGAID = "ACCESS_LIMITED_TO_ORGANISATORISCHEEINHEITENID-bin"; - - public static final Context.Key<ArchiveCallContext> CONTEXT_KEY_CALL_CONTEXT = Context.key("archiveCallContext"); - - @Override - public <A, B> Listener<A> interceptCall(ServerCall<A, B> call, Metadata headers, ServerCallHandler<A, B> next) { - var newContext = Context.current().withValue(CONTEXT_KEY_CALL_CONTEXT, createArchiveCallContext(headers)); - return Contexts.interceptCall(newContext, call, headers, next); - } - - ArchiveCallContext createArchiveCallContext(Metadata headers) { - return ArchiveCallContext.builder() - .userId(getFromHeaders(KEY_USER_ID, headers).orElse(StringUtils.EMPTY)) - .accessLimited(getFromHeaders(KEY_ACCESS_LIMITED, headers).map(isLimited -> isLimited.equals("true")).orElse(false)) - .accessLimitedToOrgaIds(getCollection(KEY_ACCESS_LIMITED_ORGAID, headers)) - .build(); - } -} diff --git a/archive-manager-server/src/main/java/de/ozgcloud/archive/common/callcontext/CallContextMapper.java b/archive-manager-server/src/main/java/de/ozgcloud/archive/common/callcontext/CallContextMapper.java new file mode 100644 index 0000000000000000000000000000000000000000..5731f307fa3e96f9c59692bb28da2b33665031ba --- /dev/null +++ b/archive-manager-server/src/main/java/de/ozgcloud/archive/common/callcontext/CallContextMapper.java @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2024 Das Land Schleswig-Holstein vertreten durch den + * Ministerpräsidenten des Landes Schleswig-Holstein + * Staatskanzlei + * Abteilung Digitalisierung und zentrales IT-Management der Landesregierung + * + * 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.archive.common.callcontext; + +import org.mapstruct.AnnotateWith; +import org.mapstruct.CollectionMappingStrategy; +import org.mapstruct.Mapper; +import org.mapstruct.Mapping; +import org.springframework.stereotype.Component; + +import de.ozgcloud.apilib.common.callcontext.CallContext; +import de.ozgcloud.archive.ArchiveManagerConfiguration; +import de.ozgcloud.archive.common.user.OzgCloudUserIdMapper; +import de.ozgcloud.common.grpc.GrpcUtil; +import io.grpc.Metadata; +import lombok.extern.log4j.Log4j2; + +@Mapper(uses = OzgCloudUserIdMapper.class, collectionMappingStrategy = CollectionMappingStrategy.ADDER_PREFERRED) +@AnnotateWith(value = Component.class, elements = @AnnotateWith.Element(strings = ArchiveManagerConfiguration.CALL_CONTEXT_MAPPER_NAME)) +@Log4j2 +abstract class CallContextMapper { // NOSONAR + + @Mapping(target = "accessLimitedToOrgaId", ignore = true) + @Mapping(target = "clientName", constant = CallContextUser.ARCHIVE_MANAGER_CLIENT_NAME) + abstract CallContext toOzgCloudCallContext(CallContextUser callContextUser); + + public CallContextUser toCallContextUser(Metadata headers, String requestId) { + var builder = CallContextUser.builder() + .requestId(requestId) + .userId(GrpcUtil.getUserId(headers)) + .userName(GrpcUtil.getUserName(headers)); + GrpcUtil.getAccessLimited(headers).ifPresentOrElse( + isAccessLimited -> builder.accessLimited(isAccessLimited).accessLimitedToOrgaIds(GrpcUtil.getAccessLimitedOrgaIds(headers)), + () -> builder.accessLimited(false)); + // TODO throw exception if missing required data as soon all clients are fine + GrpcUtil.getClientName(headers).ifPresentOrElse(builder::clientName, () -> LOG.warn("Missing client name in grpc header.")); + return builder.build(); + } +} diff --git a/archive-manager-server/src/main/java/de/ozgcloud/archive/common/callcontext/CallContextProvider.java b/archive-manager-server/src/main/java/de/ozgcloud/archive/common/callcontext/CallContextProvider.java index 5ce75ee17473a0f65c2483dc18cc1c2ec7f8a718..9fd0d350ed11048aded7be7715f289c52cf6c941 100644 --- a/archive-manager-server/src/main/java/de/ozgcloud/archive/common/callcontext/CallContextProvider.java +++ b/archive-manager-server/src/main/java/de/ozgcloud/archive/common/callcontext/CallContextProvider.java @@ -1,18 +1,24 @@ package de.ozgcloud.archive.common.callcontext; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.stereotype.Component; + import de.ozgcloud.apilib.common.callcontext.CallContext; import de.ozgcloud.apilib.common.callcontext.OzgCloudCallContextProvider; +import de.ozgcloud.archive.ArchiveManagerConfiguration; import lombok.RequiredArgsConstructor; +@Component(ArchiveManagerConfiguration.CALL_CONTEXT_PROVIDER_NAME) // NOSONAR @RequiredArgsConstructor public class CallContextProvider implements OzgCloudCallContextProvider { - private final ArchiveCallContextMapper mapper; - private final GrpcCallContextSupplier contextSupplier; + @Qualifier(ArchiveManagerConfiguration.CURRENT_USER_SERVICE_NAME) // NOSONAR + private final CurrentUserService currentUserService; + @Qualifier(ArchiveManagerConfiguration.CALL_CONTEXT_MAPPER_NAME) // NOSONAR + private final CallContextMapper mapper; @Override public CallContext provideContext() { - var archiveCallContext = contextSupplier.get(); - return mapper.toOzgCloudCallContext(archiveCallContext); + return mapper.toOzgCloudCallContext(currentUserService.getUser()); } } diff --git a/archive-manager-server/src/main/java/de/ozgcloud/archive/common/callcontext/CallContextUser.java b/archive-manager-server/src/main/java/de/ozgcloud/archive/common/callcontext/CallContextUser.java index baca08b2a58088decfde17f8fc3559e266dc56e0..0d74bf0b07f69f8f5ca9da3b1805f4483147716a 100644 --- a/archive-manager-server/src/main/java/de/ozgcloud/archive/common/callcontext/CallContextUser.java +++ b/archive-manager-server/src/main/java/de/ozgcloud/archive/common/callcontext/CallContextUser.java @@ -1,28 +1,6 @@ -/* - * Copyright (C) 2024 Das Land Schleswig-Holstein vertreten durch den - * Ministerpräsidenten des Landes Schleswig-Holstein - * Staatskanzlei - * Abteilung Digitalisierung und zentrales IT-Management der Landesregierung - * - * 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.archive.common.callcontext; +import java.io.Serial; import java.io.Serializable; import java.util.Collection; import java.util.Optional; @@ -37,21 +15,27 @@ import lombok.Singular; @Getter public class CallContextUser implements AuthenticatedPrincipal, Serializable { + public static final String ARCHIVE_MANAGER_CLIENT_NAME = "OzgCloud_ArchiveManager"; + + @Serial private static final long serialVersionUID = 1L; - private final String clientName; + private String requestId; + + private String clientName; @Builder.Default - private final transient Optional<String> userId = Optional.empty(); + private Optional<String> userId = Optional.empty(); @Builder.Default - private final transient Optional<String> userName = Optional.empty(); - @Singular - private final Collection<String> organisatorischeEinheitenIds; + private Optional<String> userName = Optional.empty(); @Builder.Default - private final transient boolean organisationEinheitenIdCheckNecessary = false; + private boolean accessLimited = false; + + @Singular + private Collection<String> accessLimitedToOrgaIds; @Override public String getName() { return clientName; } -} \ No newline at end of file +} diff --git a/archive-manager-server/src/main/java/de/ozgcloud/archive/common/callcontext/CurrentUserService.java b/archive-manager-server/src/main/java/de/ozgcloud/archive/common/callcontext/CurrentUserService.java index b45454745ceb121335ab490e531f094732b74eb2..07e867d69de62efecc026ddec84cf92644a3e241 100644 --- a/archive-manager-server/src/main/java/de/ozgcloud/archive/common/callcontext/CurrentUserService.java +++ b/archive-manager-server/src/main/java/de/ozgcloud/archive/common/callcontext/CurrentUserService.java @@ -25,9 +25,10 @@ package de.ozgcloud.archive.common.callcontext; import java.util.Objects; import java.util.Optional; -import java.util.stream.Collectors; +import java.util.UUID; import org.apache.commons.lang3.StringUtils; +import org.apache.logging.log4j.ThreadContext; import org.springframework.security.authentication.AuthenticationTrustResolver; import org.springframework.security.core.Authentication; import org.springframework.security.core.GrantedAuthority; @@ -37,6 +38,7 @@ import org.springframework.stereotype.Service; import de.ozgcloud.archive.ArchiveManagerConfiguration; import de.ozgcloud.command.Command; +import de.ozgcloud.common.grpc.GrpcUtil; import lombok.RequiredArgsConstructor; @RequiredArgsConstructor @@ -56,16 +58,14 @@ public class CurrentUserService { .filter(user -> StringUtils.isNotBlank(user.getClientName())); } - private CallContextUser mapToCallContextUser(Authentication auth) { - if (auth instanceof CallContextAuthenticationToken) { - return (CallContextUser) auth.getPrincipal(); - } else { - return CallContextUser.builder() - .clientName(auth.getName()) - .organisatorischeEinheitenIds( - auth.getAuthorities().stream().map(GrantedAuthority::getAuthority).collect(Collectors.toUnmodifiableSet())) - .build(); - } + CallContextUser mapToCallContextUser(Authentication auth) { + return auth instanceof CallContextAuthenticationToken token ? token.getUser() : buildDefaultCallContextUser(auth); + } + + CallContextUser buildDefaultCallContextUser(Authentication auth) { + var defaultContextUser = CallContextUser.builder().clientName(auth.getName()); + auth.getAuthorities().stream().map(GrantedAuthority::getAuthority).forEach(defaultContextUser::accessLimitedToOrgaId); + return defaultContextUser.build(); } public Optional<Authentication> findAuthentication() { @@ -79,23 +79,32 @@ public class CurrentUserService { .filter(Authentication::isAuthenticated); } - public SecurityContext startSecurityContext(Command command) { - var prevContext = SecurityContextHolder.getContext(); - - SecurityContextHolder.clearContext(); - SecurityContextHolder.getContext().setAuthentication(CallContextAuthenticationToken.authenticate(createUser(command))); - - return prevContext; + public SecurityContext startAndReturnPreviousSecurityContext(Command command) { + return startAndReturnPreviousSecurityContext(createUser(command)); } CallContextUser createUser(Command command) { - var builder = CallContextUser.builder() + return CallContextUser.builder() .userId(Optional.ofNullable(command.getCreatedBy())) .userName(Optional.ofNullable(command.getCreatedByName())) .clientName(command.getCreatedByClientName()) - .organisationEinheitenIdCheckNecessary(false); + .requestId(getRequestId()) + .accessLimited(false) + .build(); + } - return builder.build(); + String getRequestId() { + return ThreadContext.getContext().getOrDefault(GrpcUtil.KEY_REQUEST_ID, UUID.randomUUID().toString()); + } + + + public SecurityContext startAndReturnPreviousSecurityContext(CallContextUser user) { + var prevContext = SecurityContextHolder.getContext(); + + SecurityContextHolder.clearContext(); + SecurityContextHolder.getContext().setAuthentication(CallContextAuthenticationToken.authenticate(user)); + + return prevContext; } public void resetSecurityContext(SecurityContext context) { diff --git a/archive-manager-server/src/main/java/de/ozgcloud/archive/common/callcontext/GrpcCallContextSupplier.java b/archive-manager-server/src/main/java/de/ozgcloud/archive/common/callcontext/GrpcCallContextSupplier.java deleted file mode 100644 index a5237a7877c7805d6724a480b3062a257028dadb..0000000000000000000000000000000000000000 --- a/archive-manager-server/src/main/java/de/ozgcloud/archive/common/callcontext/GrpcCallContextSupplier.java +++ /dev/null @@ -1,7 +0,0 @@ -package de.ozgcloud.archive.common.callcontext; - -import java.util.function.Supplier; - -interface GrpcCallContextSupplier extends Supplier<ArchiveCallContext> { - -} diff --git a/archive-manager-server/src/main/java/de/ozgcloud/archive/common/command/CommandRemoteService.java b/archive-manager-server/src/main/java/de/ozgcloud/archive/common/command/CommandRemoteService.java index 5f108c823fff0b6741058edc2e7ac069ebc0eff4..30737473d4f5ecf767f9abdaa55e193aaac5698f 100644 --- a/archive-manager-server/src/main/java/de/ozgcloud/archive/common/command/CommandRemoteService.java +++ b/archive-manager-server/src/main/java/de/ozgcloud/archive/common/command/CommandRemoteService.java @@ -3,33 +3,30 @@ package de.ozgcloud.archive.common.command; import java.util.Optional; import java.util.stream.Stream; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.stereotype.Service; import de.ozgcloud.apilib.common.callcontext.OzgCloudCallContextAttachingInterceptor; import de.ozgcloud.apilib.common.callcontext.OzgCloudCallContextProvider; import de.ozgcloud.archive.ArchiveManagerConfiguration; -import de.ozgcloud.archive.common.GrpcUtil; -import de.ozgcloud.command.Command; import de.ozgcloud.vorgang.grpc.command.CommandServiceGrpc.CommandServiceBlockingStub; import de.ozgcloud.vorgang.grpc.command.GrpcExistsPendingCommandsRequest; import de.ozgcloud.vorgang.grpc.command.GrpcFindCommandsRequest; +import lombok.RequiredArgsConstructor; import net.devh.boot.grpc.client.inject.GrpcClient; +@RequiredArgsConstructor @Service(ArchiveManagerConfiguration.COMMAND_REMOTE_SERVICE_NAME) // NOSONAR class CommandRemoteService { - @GrpcClient(GrpcUtil.VORGANG_MANAGER_GRPC_CLIENT) - private CommandServiceBlockingStub grpcService; - @Autowired + @GrpcClient(ArchiveManagerConfiguration.GRPC_VORGANG_MANAGER_CLIENT_NAME) // NOSONAR + private final CommandServiceBlockingStub grpcService; @Qualifier(ArchiveManagerConfiguration.COMMAND_MAPPER_NAME) // NOSONAR - private CommandMapper mapper; - @Autowired - @Qualifier(ArchiveManagerConfiguration.OZGCLOUD_CALL_CONTEXT_PROVIDER_NAME) - private OzgCloudCallContextProvider contextProvider; + private final CommandMapper mapper; + @Qualifier(ArchiveManagerConfiguration.CALL_CONTEXT_PROVIDER_NAME) // NOSONAR + private final OzgCloudCallContextProvider contextProvider; - public Stream<Command> findCommands(String vorgangId, Optional<String> status, Optional<String> order) { + public Stream<ArchiveManagerCommand> findCommands(String vorgangId, Optional<String> status, Optional<String> order) { var response = getGrpcServiceWithInterceptor().findCommands(buildFindCommandsRequest(vorgangId, status, order)); return response.getCommandList().stream().map(mapper::fromGrpc); diff --git a/archive-manager-server/src/main/java/de/ozgcloud/archive/common/command/CommandService.java b/archive-manager-server/src/main/java/de/ozgcloud/archive/common/command/CommandService.java index a6b4fa22312cf7fd9e4a239dd30474483fab3721..87ec01c91c8a18da8fad5f749702e028ce955ae9 100644 --- a/archive-manager-server/src/main/java/de/ozgcloud/archive/common/command/CommandService.java +++ b/archive-manager-server/src/main/java/de/ozgcloud/archive/common/command/CommandService.java @@ -1,13 +1,17 @@ package de.ozgcloud.archive.common.command; import java.util.Optional; +import java.util.function.Predicate; import java.util.stream.Stream; +import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.stereotype.Service; +import de.ozgcloud.apilib.common.command.OzgCloudCommand; +import de.ozgcloud.apilib.common.command.OzgCloudCommandService; +import de.ozgcloud.apilib.vorgang.OzgCloudVorgangId; import de.ozgcloud.archive.ArchiveManagerConfiguration; -import de.ozgcloud.command.Command; import de.ozgcloud.command.CommandStatus; import lombok.NonNull; import lombok.RequiredArgsConstructor; @@ -18,8 +22,10 @@ public class CommandService { @Qualifier(ArchiveManagerConfiguration.COMMAND_REMOTE_SERVICE_NAME) // NOSONAR private final CommandRemoteService remoteService; + @Qualifier(ArchiveManagerConfiguration.OZGCLOUD_COMMAND_SERVICE_NAME) // NOSONAR + private final OzgCloudCommandService ozgCloudCommandService; - public Stream<Command> findPending(String vorgangId, CommandOrder order) { + public Stream<ArchiveManagerCommand> findPending(String vorgangId, CommandOrder order) { return remoteService.findCommands(vorgangId, Optional.of(CommandStatus.PENDING.name()), Optional.of(order.name())); } @@ -28,7 +34,12 @@ public class CommandService { .map(ArchiveManagerCommand.class::cast); } - public boolean hasPendingCommands(String vorgangId) { - return remoteService.hasPendingCommands(vorgangId); + public boolean hasPendingCommandsExceptWithOrder(String vorgangId, String order) { + var pendingCommands = ozgCloudCommandService.getPendingCommands(OzgCloudVorgangId.from(vorgangId)); + return pendingCommands.stream().anyMatch(hasNotOrder(order)); + } + + private Predicate<? super OzgCloudCommand> hasNotOrder(String order) { + return command -> !StringUtils.equals(command.getOrder(), order); } } \ No newline at end of file diff --git a/archive-manager-server/src/main/java/de/ozgcloud/archive/common/user/OzgCloudUserIdMapper.java b/archive-manager-server/src/main/java/de/ozgcloud/archive/common/user/OzgCloudUserIdMapper.java index d662419ad8a5e575b713e40fe9a09ba927688404..0c41a4e443df0290a12785c043df33b28068b7af 100644 --- a/archive-manager-server/src/main/java/de/ozgcloud/archive/common/user/OzgCloudUserIdMapper.java +++ b/archive-manager-server/src/main/java/de/ozgcloud/archive/common/user/OzgCloudUserIdMapper.java @@ -1,5 +1,7 @@ package de.ozgcloud.archive.common.user; +import java.util.Optional; + import org.mapstruct.Mapper; import de.ozgcloud.apilib.user.OzgCloudUserId; @@ -7,6 +9,10 @@ import de.ozgcloud.apilib.user.OzgCloudUserId; @Mapper public interface OzgCloudUserIdMapper { + default OzgCloudUserId fromString(Optional<String> id) { + return id.map(this::fromString).orElse(null); + } + default OzgCloudUserId fromString(String id) { return OzgCloudUserId.from(id); } diff --git a/archive-manager-server/src/main/java/de/ozgcloud/archive/common/xta/JsonToXtaIdentifierListConverter.java b/archive-manager-server/src/main/java/de/ozgcloud/archive/common/xta/JsonToXtaIdentifierListConverter.java new file mode 100644 index 0000000000000000000000000000000000000000..d112b2c26dbfe68d4d97b819afd6a9b667e20549 --- /dev/null +++ b/archive-manager-server/src/main/java/de/ozgcloud/archive/common/xta/JsonToXtaIdentifierListConverter.java @@ -0,0 +1,34 @@ +package de.ozgcloud.archive.common.xta; + +import java.util.List; + +import org.springframework.boot.context.properties.ConfigurationPropertiesBinding; +import org.springframework.core.convert.converter.Converter; +import org.springframework.stereotype.Component; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.ObjectMapper; + +import de.ozgcloud.common.errorhandling.TechnicalException; +import de.ozgcloud.xta.client.model.XtaIdentifier; +import lombok.RequiredArgsConstructor; + +@Component +@ConfigurationPropertiesBinding +@RequiredArgsConstructor +public class JsonToXtaIdentifierListConverter implements Converter<String, List<XtaIdentifier>> { + + private final ObjectMapper objectMapper; + + @Override + public List<XtaIdentifier> convert(String source) { + try { + return objectMapper.readValue(source, new TypeReference<List<XtaIdentifier>>() { + }); + } catch (JsonProcessingException e) { + throw new TechnicalException("Error on converting XtaIdentifier!", e); + } + } + +} diff --git a/archive-manager-server/src/main/java/de/ozgcloud/archive/common/xta/XtaConfiguration.java b/archive-manager-server/src/main/java/de/ozgcloud/archive/common/xta/XtaConfiguration.java new file mode 100644 index 0000000000000000000000000000000000000000..a58411a47551496e1813c02934e5310ef4c91188 --- /dev/null +++ b/archive-manager-server/src/main/java/de/ozgcloud/archive/common/xta/XtaConfiguration.java @@ -0,0 +1,61 @@ +package de.ozgcloud.archive.common.xta; + +import java.io.IOException; + +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Lazy; + +import com.fasterxml.jackson.databind.ObjectMapper; + +import de.ozgcloud.archive.common.xta.XtaProperties.XtaClientKeyStore; +import de.ozgcloud.common.errorhandling.TechnicalException; +import de.ozgcloud.xta.client.XtaClient; +import de.ozgcloud.xta.client.config.XtaClientConfig; +import de.ozgcloud.xta.client.config.XtaClientConfig.KeyStore; +import de.ozgcloud.xta.client.exception.XtaClientInitializationException; + +@Configuration +class XtaConfiguration { + + @Bean + @ConditionalOnProperty(prefix = XtaProperties.XTA_PROPERTIES_PREFIX, name = "enabled") + XtaClient xtaClient(XtaProperties xtaProperties) { + try { + return XtaClient.from(buildXtaClientConfig(xtaProperties)); + } catch (XtaClientInitializationException e) { + throw new TechnicalException("Error on initializing Xta client.", e); + } + } + + XtaClientConfig buildXtaClientConfig(XtaProperties xtaProperties) { + return XtaClientConfig.builder() + .sendServiceUrl(xtaProperties.getSendServiceUrl()) + .managementServiceUrl(xtaProperties.getManagementServiceUrl()) + .msgBoxServiceUrl(xtaProperties.getMsgBoxServiceUrl()) + .clientCertKeystore(buildKeystore(xtaProperties.getKeyStore())) + .trustStore(buildKeystore(xtaProperties.getTrustStore())) + .maxListItems(xtaProperties.getMaxListItems()) + .clientIdentifiers(xtaProperties.getClientIdentifiers()) + .build(); + } + + private KeyStore buildKeystore(XtaClientKeyStore clientCert) { + try { + return XtaClientConfig.KeyStore.builder() + .content(clientCert.getFile().getContentAsByteArray()) + .type(clientCert.getType()) + .password(clientCert.getPassword()) + .build(); + } catch (IOException e) { + throw new TechnicalException("Error on reading Xta client certificate.", e); + } + } + + @Bean + @Lazy + ObjectMapper objectMapper() { + return new ObjectMapper(); + } +} diff --git a/archive-manager-server/src/main/java/de/ozgcloud/archive/XtaProperties.java b/archive-manager-server/src/main/java/de/ozgcloud/archive/common/xta/XtaProperties.java similarity index 52% rename from archive-manager-server/src/main/java/de/ozgcloud/archive/XtaProperties.java rename to archive-manager-server/src/main/java/de/ozgcloud/archive/common/xta/XtaProperties.java index 2084814f8fefdc6b5b0460cfc639dad861129199..678fe4036516ee34edc6128065096472798e4744 100644 --- a/archive-manager-server/src/main/java/de/ozgcloud/archive/XtaProperties.java +++ b/archive-manager-server/src/main/java/de/ozgcloud/archive/common/xta/XtaProperties.java @@ -1,4 +1,4 @@ -package de.ozgcloud.archive; +package de.ozgcloud.archive.common.xta; import java.util.List; @@ -17,11 +17,38 @@ import lombok.Setter; public class XtaProperties { static final String XTA_PROPERTIES_PREFIX = "ozgcloud.xta"; + + /* + * Flag to enable/disable XTA adapter usage. + */ + private boolean enabled = false; + /* + * XTA endpoint messages are sent to. + */ private String sendServiceUrl; + /* + * XTA endpoint to message box. + */ private String msgBoxServiceUrl; + /* + * XTA endpoint to management information + */ private String managementServiceUrl; - private int maxListItems; + /* + * Maximum number of Messages loaded from message box. + */ + private int maxListItems = 50; + /* + * Reference to client certifiaction key store. + */ private XtaClientKeyStore keyStore; + /* + * Reference to trust store. + */ + private XtaClientKeyStore trustStore; + /* + * Client identifiers used to identify cleint at XTA adapter. + */ private List<XtaIdentifier> clientIdentifiers; private String schedulerCron; @@ -29,8 +56,17 @@ public class XtaProperties { @Getter @Setter public static class XtaClientKeyStore { + /* + * Reference to key store reference. + */ private Resource file; - private String type = "PKCS12"; + /* + * Type of the referenced key store. + */ + private String type; + /* + * Password to access key store. + */ private char[] password; } } diff --git a/archive-manager-server/src/main/java/de/ozgcloud/archive/common/xta/XtaService.java b/archive-manager-server/src/main/java/de/ozgcloud/archive/common/xta/XtaService.java new file mode 100644 index 0000000000000000000000000000000000000000..9aac41082bcaaa23dbb2b1acbadaf85411791ef5 --- /dev/null +++ b/archive-manager-server/src/main/java/de/ozgcloud/archive/common/xta/XtaService.java @@ -0,0 +1,41 @@ +package de.ozgcloud.archive.common.xta; + +import java.util.Optional; + +import org.springframework.stereotype.Service; + +import de.ozgcloud.common.errorhandling.TechnicalException; +import de.ozgcloud.xta.client.XtaClient; +import de.ozgcloud.xta.client.exception.XtaClientException; +import de.ozgcloud.xta.client.model.XtaFile; +import de.ozgcloud.xta.client.model.XtaMessage; +import de.ozgcloud.xta.client.xdomea.XdomeaXtaMessageCreator; +import lombok.RequiredArgsConstructor; + +@RequiredArgsConstructor +@Service +public class XtaService { + private static final String XTA_CLIENT_IS_NOT_CONFIGURED_MESSAGE = "XtaClient is not configured! Cannot send message to DMS."; + + private final Optional<XtaClient> xtaClient; + + public void sendXdomeaFile(XtaFile xdomeaFile) { + try { + getXtaClient().sendMessage(createMessage(xdomeaFile)); + } catch (XtaClientException e) { + throw new TechnicalException("Error on sending xDomea message!", e); + } + } + + XtaMessage createMessage(XtaFile xdomeaFile) { + try { + return XdomeaXtaMessageCreator.createInstance().createMessage(xdomeaFile); + } catch (XtaClientException e) { + throw new TechnicalException("Error on creating xDomea message!", e); + } + } + + XtaClient getXtaClient() { + return xtaClient.orElseThrow(() -> new TechnicalException(XTA_CLIENT_IS_NOT_CONFIGURED_MESSAGE)); + } +} diff --git a/archive-manager-server/src/main/java/de/ozgcloud/archive/export/ExportGrpcService.java b/archive-manager-server/src/main/java/de/ozgcloud/archive/export/ExportGrpcService.java index 0af9d44fe26c1f9cc92d6c0af711c4200b53b283..4044d715486da1fa0487d400a1b3501fc4c8dec0 100644 --- a/archive-manager-server/src/main/java/de/ozgcloud/archive/export/ExportGrpcService.java +++ b/archive-manager-server/src/main/java/de/ozgcloud/archive/export/ExportGrpcService.java @@ -6,7 +6,7 @@ import org.springframework.core.task.TaskExecutor; import com.google.protobuf.ByteString; -import de.ozgcloud.archive.common.callcontext.CallContextInterceptor; +import de.ozgcloud.archive.ArchiveManagerConfiguration; import de.ozgcloud.archive.grpc.export.ExportServiceGrpc.ExportServiceImplBase; import de.ozgcloud.archive.grpc.export.GrpcExportVorgangRequest; import de.ozgcloud.archive.grpc.export.GrpcExportVorgangResponse; @@ -17,7 +17,7 @@ import io.grpc.stub.StreamObserver; import lombok.RequiredArgsConstructor; import net.devh.boot.grpc.server.service.GrpcService; -@GrpcService(interceptors = { CallContextInterceptor.class }) +@GrpcService(interceptorNames = { ArchiveManagerConfiguration.CALL_CONTEXT_SERVER_INTERCEPTOR_NAME }) @RequiredArgsConstructor class ExportGrpcService extends ExportServiceImplBase { diff --git a/archive-manager-server/src/main/java/de/ozgcloud/archive/export/ExportService.java b/archive-manager-server/src/main/java/de/ozgcloud/archive/export/ExportService.java index 169d99df79b822219f4e83c9950f839bba999e99..1aba00ad27c8df1d694853f33ebb8e8d67286060 100644 --- a/archive-manager-server/src/main/java/de/ozgcloud/archive/export/ExportService.java +++ b/archive-manager-server/src/main/java/de/ozgcloud/archive/export/ExportService.java @@ -1,21 +1,29 @@ package de.ozgcloud.archive.export; +import java.io.File; import java.io.IOException; import java.io.OutputStream; import java.nio.charset.StandardCharsets; import java.util.Optional; import java.util.Set; +import java.util.UUID; import java.util.function.Function; import java.util.stream.Collectors; import java.util.stream.Stream; import java.util.zip.ZipEntry; import java.util.zip.ZipOutputStream; +import jakarta.activation.DataHandler; +import jakarta.activation.FileDataSource; + import org.apache.commons.lang3.StringUtils; +import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.stereotype.Service; +import de.ozgcloud.archive.ArchiveManagerConfiguration; import de.ozgcloud.archive.bescheid.ExportBescheidService; import de.ozgcloud.archive.common.ExportFilenameGenerator; +import de.ozgcloud.archive.common.xta.XtaService; import de.ozgcloud.archive.file.ExportFileService; import de.ozgcloud.archive.file.OzgFile; import de.ozgcloud.archive.historie.ExportHistorieService; @@ -23,9 +31,11 @@ import de.ozgcloud.archive.kommentar.ExportKommentarService; import de.ozgcloud.archive.postfach.ExportNachrichtService; import de.ozgcloud.archive.vorgang.Eingang; import de.ozgcloud.archive.vorgang.EingangHeader; -import de.ozgcloud.archive.vorgang.ExportVorgangService; +import de.ozgcloud.archive.vorgang.VorgangService; import de.ozgcloud.archive.vorgang.VorgangWithEingang; +import de.ozgcloud.command.Command; import de.ozgcloud.common.errorhandling.TechnicalException; +import de.ozgcloud.xta.client.model.XtaFile; import de.xoev.xdomea.AbgabeAbgabe0401; import lombok.RequiredArgsConstructor; @@ -40,11 +50,52 @@ public class ExportService { private final XdomeaXmlMarshaller xDomeaXmlMarshaller; private final ExportFileService exportFileService; - private final ExportVorgangService exportVorgangService; + @Qualifier(ArchiveManagerConfiguration.VORGANG_SERVICE_NAME) // NOSONAR + private final VorgangService vorgangService; private final ExportHistorieService exportHistorieService; + @Qualifier(ArchiveManagerConfiguration.KOMMENTAR_SERVICE_NAME) // NOSONAR private final ExportKommentarService exportKommentarService; private final ExportNachrichtService exportNachrichtService; private final ExportBescheidService exportBescheidService; + private final XtaService xtaService; + + public void archiveVorgang(Command command) { + xtaService.sendXdomeaFile(buildXdomeaXtaFile(command.getVorgangId())); + } + + XtaFile buildXdomeaXtaFile(String vorgangId) { + var fileNameId = createFileNameId(); + return XtaFile.builder() + .name(buildXdomeaFileName(fileNameId)) + .content(createFileContent(vorgangId, fileNameId)) + .contentType("application/zip") + .build(); + } + + String createFileNameId() { + return UUID.randomUUID().toString(); + } + + public String buildXdomeaFileName(String fileNameId) { + return String.format(EXPORT_XDOMEA_FILENAME_TEMPLATE, fileNameId); + } + + DataHandler createFileContent(String vorgangId, String fileNameId) { + try { + var tempFile = createTempFile(fileNameId); + var fileDataSource = new FileDataSource(tempFile); + writeXdomeaFileContent(vorgangId, fileNameId, fileDataSource.getOutputStream()); + return new DataHandler(fileDataSource); + } catch (IOException e) { + throw new TechnicalException("Error on creating file content for xDomea file!", e); + } + } + + File createTempFile(String fileNameId) throws IOException { + var tempFile = File.createTempFile(fileNameId, ".zip"); + tempFile.deleteOnExit(); + return tempFile; + } public void writeXdomeaFileContent(String vorgangId, String filenameId, OutputStream outputStream) { var exportData = collectExportData(vorgangId, filenameId); @@ -52,7 +103,7 @@ public class ExportService { } ExportData collectExportData(String vorgangId, String filenameId) { - var vorgang = exportVorgangService.getVorgang(vorgangId); + var vorgang = vorgangService.getVorgang(vorgangId); var kommentarsData = exportKommentarService.createExportData(vorgang); var postfachMailData = exportNachrichtService.createExportData(vorgang); var bescheidData = exportBescheidService.createExportData(vorgang); @@ -60,9 +111,9 @@ public class ExportService { var attachments = exportFileService.getAttachments(vorgang).toList(); var formEngineName = getFormEngineName(vorgang); var abgabe = XdomeaNachrichtBuilder.builder() - .withKopf(exportVorgangService.createKopf(vorgang)) - .withVorgang(exportVorgangService.createVorgangType(vorgang)) - .withAktenzeichen(exportVorgangService.createAkteType(vorgang)) + .withKopf(vorgangService.createKopf(vorgang)) + .withVorgang(vorgangService.createVorgangType(vorgang)) + .withAktenzeichen(vorgangService.createAkteType(vorgang)) .withRepresentations(exportFileService.createDokumentTypes(representations, formEngineName).toList()) .withAttachments(exportFileService.createDokumentTypes(attachments, formEngineName).toList()) .withHistorie(exportHistorieService.createHistorienProtokollInformationTypes(vorgang).toList()) @@ -124,8 +175,4 @@ public class ExportService { throw new TechnicalException("Cannot add file to ZIP.", e); } } - - public String buildXdomeaFileName(String fileNameId) { - return String.format(EXPORT_XDOMEA_FILENAME_TEMPLATE, fileNameId); - } } diff --git a/archive-manager-server/src/main/java/de/ozgcloud/archive/file/OzgFileRemoteService.java b/archive-manager-server/src/main/java/de/ozgcloud/archive/file/OzgFileRemoteService.java index aca984a632b909c87ec502ee7e9c8b4bd9cebc91..89968a704a490af97603a2fb33bd35e0bd62e79c 100644 --- a/archive-manager-server/src/main/java/de/ozgcloud/archive/file/OzgFileRemoteService.java +++ b/archive-manager-server/src/main/java/de/ozgcloud/archive/file/OzgFileRemoteService.java @@ -2,29 +2,27 @@ package de.ozgcloud.archive.file; import java.util.stream.Stream; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.stereotype.Service; import de.ozgcloud.apilib.common.callcontext.OzgCloudCallContextAttachingInterceptor; import de.ozgcloud.apilib.common.callcontext.OzgCloudCallContextProvider; import de.ozgcloud.archive.ArchiveManagerConfiguration; -import de.ozgcloud.archive.common.GrpcUtil; import de.ozgcloud.vorgang.grpc.file.FileServiceGrpc.FileServiceBlockingStub; import de.ozgcloud.vorgang.grpc.file.GrpcGetAttachmentsRequest; import de.ozgcloud.vorgang.grpc.file.GrpcGetRepresentationsRequest; +import lombok.RequiredArgsConstructor; import net.devh.boot.grpc.client.inject.GrpcClient; @Service +@RequiredArgsConstructor class OzgFileRemoteService { - @GrpcClient(GrpcUtil.VORGANG_MANAGER_GRPC_CLIENT) - private FileServiceBlockingStub grpcService; - @Autowired - private OzgFileMapper fileMapper; - @Autowired - @Qualifier(ArchiveManagerConfiguration.OZGCLOUD_CALL_CONTEXT_PROVIDER_NAME) - private OzgCloudCallContextProvider contextProvider; + @GrpcClient(ArchiveManagerConfiguration.GRPC_VORGANG_MANAGER_CLIENT_NAME) // NOSONAR + private final FileServiceBlockingStub grpcService; + private final OzgFileMapper fileMapper; + @Qualifier(ArchiveManagerConfiguration.CALL_CONTEXT_PROVIDER_NAME) // NOSONAR + private final OzgCloudCallContextProvider contextProvider; public Stream<OzgFile> getAttachments(String vorgangId) { return getGrpcServiceWithInterceptor().getAttachments(buildGrpcGetAttachmentsRequest(vorgangId)).getFileList().stream() diff --git a/archive-manager-server/src/main/java/de/ozgcloud/archive/kommentar/ExportKommentarService.java b/archive-manager-server/src/main/java/de/ozgcloud/archive/kommentar/ExportKommentarService.java index 4790c966b921543e3982778cf65bf7e35b712699..147ca0b8104ef487ecbbd00a89f2e82553476561 100644 --- a/archive-manager-server/src/main/java/de/ozgcloud/archive/kommentar/ExportKommentarService.java +++ b/archive-manager-server/src/main/java/de/ozgcloud/archive/kommentar/ExportKommentarService.java @@ -15,10 +15,12 @@ import de.ozgcloud.archive.vorgang.VorgangWithEingang; import lombok.RequiredArgsConstructor; @RequiredArgsConstructor -@Service +@Service(ArchiveManagerConfiguration.KOMMENTAR_SERVICE_NAME) public class ExportKommentarService { + @Qualifier(ArchiveManagerConfiguration.KOMMENTAR_REMOTE_SERVICE_NAME) // NOSONAR private final KommentarRemoteService kommentarRemoteService; + @Qualifier(ArchiveManagerConfiguration.BINARY_FILE_SERVICE_NAME) // NOSONAR private final BinaryFileService binaryFileService; @Qualifier(ArchiveManagerConfiguration.USER_SERVICE_NAME) // NOSONAR private final UserService userService; diff --git a/archive-manager-server/src/main/java/de/ozgcloud/archive/kommentar/KommentarRemoteService.java b/archive-manager-server/src/main/java/de/ozgcloud/archive/kommentar/KommentarRemoteService.java index 0fc1e206b70090a2ab26a0714d44139c5c1bad26..f42be6e0c777fbae782c822e3cef108d7ec812f1 100644 --- a/archive-manager-server/src/main/java/de/ozgcloud/archive/kommentar/KommentarRemoteService.java +++ b/archive-manager-server/src/main/java/de/ozgcloud/archive/kommentar/KommentarRemoteService.java @@ -25,30 +25,28 @@ package de.ozgcloud.archive.kommentar; import java.util.stream.Stream; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.stereotype.Service; import de.ozgcloud.apilib.common.callcontext.OzgCloudCallContextAttachingInterceptor; import de.ozgcloud.apilib.common.callcontext.OzgCloudCallContextProvider; import de.ozgcloud.archive.ArchiveManagerConfiguration; -import de.ozgcloud.archive.common.GrpcUtil; import de.ozgcloud.vorgang.vorgangAttachedItem.GrpcFindVorgangAttachedItemRequest; import de.ozgcloud.vorgang.vorgangAttachedItem.VorgangAttachedItemServiceGrpc.VorgangAttachedItemServiceBlockingStub; +import lombok.RequiredArgsConstructor; import net.devh.boot.grpc.client.inject.GrpcClient; -@Service +@Service(ArchiveManagerConfiguration.KOMMENTAR_REMOTE_SERVICE_NAME) // NOSONAR +@RequiredArgsConstructor class KommentarRemoteService { static final String ITEM_NAME = "Kommentar"; - @GrpcClient(GrpcUtil.VORGANG_MANAGER_GRPC_CLIENT) - private VorgangAttachedItemServiceBlockingStub grpcService; - @Autowired - private KommentarMapper mapper; - @Autowired - @Qualifier(ArchiveManagerConfiguration.OZGCLOUD_CALL_CONTEXT_PROVIDER_NAME) - private OzgCloudCallContextProvider contextProvider; + @GrpcClient(ArchiveManagerConfiguration.GRPC_VORGANG_MANAGER_CLIENT_NAME) + private final VorgangAttachedItemServiceBlockingStub grpcService; + private final KommentarMapper mapper; + @Qualifier(ArchiveManagerConfiguration.CALL_CONTEXT_PROVIDER_NAME) // NOSONAR + private final OzgCloudCallContextProvider contextProvider; public Stream<Kommentar> findByVorgangId(String vorgangId) { var response = getGrpcServiceWithInterceptor().find(buildFindRequest(vorgangId)); diff --git a/archive-manager-server/src/main/java/de/ozgcloud/archive/postfach/PostfachMailMapper.java b/archive-manager-server/src/main/java/de/ozgcloud/archive/postfach/PostfachMailMapper.java index 97aa69608ea3e5868d60118525b6200a570dbe75..85c5806c361a24443e04d784a2e79bfee1ee8936 100644 --- a/archive-manager-server/src/main/java/de/ozgcloud/archive/postfach/PostfachMailMapper.java +++ b/archive-manager-server/src/main/java/de/ozgcloud/archive/postfach/PostfachMailMapper.java @@ -25,6 +25,7 @@ package de.ozgcloud.archive.postfach; import java.util.List; +import org.apache.commons.lang3.StringUtils; import org.mapstruct.Mapper; import org.mapstruct.Mapping; import org.mapstruct.MappingConstants; @@ -37,7 +38,7 @@ import de.ozgcloud.archive.common.TimeMapper; import de.ozgcloud.common.binaryfile.FileId; import de.ozgcloud.nachrichten.postfach.GrpcPostfachMail; -@Mapper(nullValueCheckStrategy = NullValueCheckStrategy.ALWAYS, uses = TimeMapper.class) +@Mapper(nullValueCheckStrategy = NullValueCheckStrategy.ALWAYS, uses = TimeMapper.class, imports = StringUtils.class) interface PostfachMailMapper { @Mapping(target = "attachment", ignore = true) @@ -45,6 +46,7 @@ interface PostfachMailMapper { @ValueMapping(target = MappingConstants.NULL, source = "UNRECOGNIZED") @ValueMapping(target = MappingConstants.NULL, source = "UNDEFINED") @Mapping(target = "attachments", source = "attachmentList") + @Mapping(target = "createdBy", expression = "java(StringUtils.trimToNull(grpcPostfachMail.getCreatedBy()))") PostfachMail toPostfachMail(GrpcPostfachMail grpcPostfachMail); default List<FileId> fromStringList(ProtocolStringList stringList) { diff --git a/archive-manager-server/src/main/java/de/ozgcloud/archive/postfach/PostfachMailRemoteService.java b/archive-manager-server/src/main/java/de/ozgcloud/archive/postfach/PostfachMailRemoteService.java index 26cf2d7e8d59fe78ed1a627265ac5e9a7ce15c75..6510a7cb91cde5ac1a01751cdc2b636b5696ba4e 100644 --- a/archive-manager-server/src/main/java/de/ozgcloud/archive/postfach/PostfachMailRemoteService.java +++ b/archive-manager-server/src/main/java/de/ozgcloud/archive/postfach/PostfachMailRemoteService.java @@ -28,7 +28,7 @@ import java.util.stream.Stream; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; -import de.ozgcloud.archive.common.GrpcUtil; +import de.ozgcloud.archive.ArchiveManagerConfiguration; import de.ozgcloud.nachrichten.postfach.GrpcFindPostfachMailsRequest; import de.ozgcloud.nachrichten.postfach.PostfachServiceGrpc.PostfachServiceBlockingStub; import net.devh.boot.grpc.client.inject.GrpcClient; @@ -36,7 +36,7 @@ import net.devh.boot.grpc.client.inject.GrpcClient; @Service class PostfachMailRemoteService { - @GrpcClient(GrpcUtil.VORGANG_MANAGER_GRPC_CLIENT) + @GrpcClient(ArchiveManagerConfiguration.GRPC_VORGANG_MANAGER_CLIENT_NAME) private PostfachServiceBlockingStub grpcService; @Autowired private PostfachMailMapper postfachNachrichtMapper; diff --git a/archive-manager-server/src/main/java/de/ozgcloud/archive/vorgang/ArchiveEventListener.java b/archive-manager-server/src/main/java/de/ozgcloud/archive/vorgang/ArchiveEventListener.java index c071f50160f310d78427af76b6d2f21f265da6c0..e863cb332126c190d4808cdc5c65a64777c0a2ad 100644 --- a/archive-manager-server/src/main/java/de/ozgcloud/archive/vorgang/ArchiveEventListener.java +++ b/archive-manager-server/src/main/java/de/ozgcloud/archive/vorgang/ArchiveEventListener.java @@ -23,16 +23,9 @@ */ package de.ozgcloud.archive.vorgang; -import java.io.File; -import java.io.IOException; -import java.util.Optional; -import java.util.UUID; import java.util.function.Consumer; import java.util.function.Predicate; -import jakarta.activation.DataHandler; -import jakarta.activation.FileDataSource; - import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.context.ApplicationEventPublisher; @@ -41,7 +34,8 @@ import org.springframework.security.core.context.SecurityContext; import org.springframework.stereotype.Component; import de.ozgcloud.archive.ArchiveManagerConfiguration; -import de.ozgcloud.archive.common.callcontext.ArchiveCallContext; +import de.ozgcloud.archive.attributes.ClientAttributeService; +import de.ozgcloud.archive.common.callcontext.CallContextUser; import de.ozgcloud.archive.common.callcontext.CurrentUserService; import de.ozgcloud.archive.common.command.CommandService; import de.ozgcloud.archive.common.errorhandling.TimeoutException; @@ -50,12 +44,6 @@ import de.ozgcloud.command.Command; import de.ozgcloud.command.CommandCreatedEvent; import de.ozgcloud.command.CommandFailedEvent; import de.ozgcloud.command.VorgangLockedEvent; -import de.ozgcloud.common.errorhandling.TechnicalException; -import de.ozgcloud.xta.client.XtaClient; -import de.ozgcloud.xta.client.exception.XtaClientException; -import de.ozgcloud.xta.client.model.XtaFile; -import de.ozgcloud.xta.client.model.XtaMessage; -import de.ozgcloud.xta.client.xdomea.XdomeaXtaMessageCreator; import lombok.RequiredArgsConstructor; import lombok.extern.log4j.Log4j2; @@ -64,124 +52,69 @@ import lombok.extern.log4j.Log4j2; @Log4j2 class ArchiveEventListener { + static final int MAXIMUM_CHECKS_FOR_PENDING_COMMANDS = 3; static final int WAIT_INTERVAL = 30 * 1000; private static final String LOG_MESSAGE_TEMPLATE = "{}. Command failed."; private static final String ERROR_MESSAGE_TEMPLATE = "Error on executing %s Command (id: %s)."; static final String ARCHIVE_VORGANG_ORDER = "ARCHIVE_VORGANG"; - private static final String IS_ARCHIVE_VORGANG_EVENT = "{T(de.ozgcloud.archive.vorgang.ArchiveEventListener)." - + "IS_ARCHIVE_VORGANG_COMMAND.test(event.getSource())}"; + private static final String IS_ARCHIVE_VORGANG_EVENT = "{T(de.ozgcloud.archive.vorgang.ArchiveEventListener).IS_ARCHIVE_VORGANG_COMMAND.test(event.getSource())}"; public static final Predicate<Command> IS_ARCHIVE_VORGANG_COMMAND = command -> ARCHIVE_VORGANG_ORDER.equals(command.getOrder()); private static final String IS_LOCKED_BY_ARCHIVE_MANAGER_EVENT = "{T(de.ozgcloud.archive.vorgang.ArchiveEventListener)." + "IS_LOCK_BY_ARCHIVE_MANAGER_COMMAND.test(event.getCommand())}"; - public static final Predicate<Command> IS_LOCK_BY_ARCHIVE_MANAGER_COMMAND = command -> ArchiveCallContext.CLIENT_NAME + public static final Predicate<Command> IS_LOCK_BY_ARCHIVE_MANAGER_COMMAND = command -> CallContextUser.ARCHIVE_MANAGER_CLIENT_NAME .equals(command.getCreatedByClientName()); @Qualifier(ArchiveManagerConfiguration.CURRENT_USER_SERVICE_NAME) // NOSONAR private final CurrentUserService currentUserService; + + @Qualifier(ArchiveManagerConfiguration.CLIENT_ATTRIBUTE_SERVICE_NAME) // NOSONAR + private final ClientAttributeService clientAttributeService; + + @Qualifier(ArchiveManagerConfiguration.VORGANG_SERVICE_NAME) // NOSONAR + private final VorgangService vorgangService; + private final ApplicationEventPublisher eventPublisher; - private final ExportService exportService; - private final Optional<XtaClient> xtaClient; private final CommandService commandService; + private final ExportService exportService; @EventListener(condition = IS_ARCHIVE_VORGANG_EVENT) void onArchiveVorgangEvent(CommandCreatedEvent event) { - runWithSecurityContext(event.getSource(), this::doArchiveVorgang); + runWithSecurityContext(event.getSource(), this::doLockVorgang); } - void doArchiveVorgang(Command command) { - } - - private String buildErrorMessage(String message, Exception cause) { - try { - StringBuilder sb = new StringBuilder(message); - if (StringUtils.isNotBlank(cause.getMessage())) { - sb.append(" Cause: ").append(cause.getMessage()); - } - return sb.toString(); - } catch (Exception e2) { - LOG.error("Error in building Error Message (sick).", e2); - return message; - } + void doLockVorgang(Command command) { + clientAttributeService.setVorgangArchiving(command.getVorgangId()); + vorgangService.lockVorgang(command); } @EventListener(condition = IS_LOCKED_BY_ARCHIVE_MANAGER_EVENT) public void onVorgangLockedEvent(VorgangLockedEvent event) { waitForPendingCommandsToFinish(event.getCommand().getVorgangId(), WAIT_INTERVAL); - runWithSecurityContext(event.getCommand(), command -> sendXdomeaFile(buildXdomeaXtaFile(command.getVorgangId()))); + runWithSecurityContext(event.getCommand(), exportService::archiveVorgang); } void waitForPendingCommandsToFinish(String vorgangId, long waitIntervalInMillis) { var numberOfAttempts = 0; - while (commandService.hasPendingCommands(vorgangId)) { + while (commandService.hasPendingCommandsExceptWithOrder(vorgangId, ARCHIVE_VORGANG_ORDER)) { numberOfAttempts++; - if (numberOfAttempts >= 3) { + if (numberOfAttempts >= MAXIMUM_CHECKS_FOR_PENDING_COMMANDS) { throw new TimeoutException("Waiting for pending commands"); } try { Thread.sleep(waitIntervalInMillis); } catch (InterruptedException e) { - LOG.error("Error while waiting for commads to finish.", e); + LOG.error("Error while waiting for commands to finish.", e); Thread.currentThread().interrupt(); } } } - XtaFile buildXdomeaXtaFile(String vorgangId) { - var fileNameId = createFileNameId(); - return XtaFile.builder() - .name(exportService.buildXdomeaFileName(fileNameId)) - .content(createFileContent(vorgangId, fileNameId)) - .contentType("application/zip") - .build(); - } - - String createFileNameId() { - return UUID.randomUUID().toString(); - } - - DataHandler createFileContent(String vorgangId, String fileNameId) { - try { - var tempFile = createTempFile(fileNameId); - var fileDataSource = new FileDataSource(tempFile); - exportService.writeXdomeaFileContent(vorgangId, fileNameId, fileDataSource.getOutputStream()); - return new DataHandler(fileDataSource); - } catch (IOException e) { - throw new TechnicalException("Error on creating file content for xDomea file!", e); - } - } - - File createTempFile(String fileNameId) throws IOException { - var tempFile = File.createTempFile(fileNameId, ".zip"); - tempFile.deleteOnExit(); - return tempFile; - } - - void sendXdomeaFile(XtaFile xdomeaFile) { - var message = createMessage(xdomeaFile); - xtaClient.ifPresentOrElse(client -> { - try { - client.sendMessage(message); - } catch (XtaClientException e) { - throw new TechnicalException("Error on sending xDomea message!", e); - } - }, () -> LOG.error("XtaClient is not configured. Cannot send message")); - - } - - XtaMessage createMessage(XtaFile xdomeaFile) { - try { - return XdomeaXtaMessageCreator.createInstance().createMessage(xdomeaFile); - } catch (XtaClientException e) { - throw new TechnicalException("Error on creating xDomea message!", e); - } - } - void runWithSecurityContext(Command command, Consumer<Command> commandExecutor) { SecurityContext prevContext = null; try { - prevContext = currentUserService.startSecurityContext(command); + prevContext = currentUserService.startAndReturnPreviousSecurityContext(command); commandExecutor.accept(command); } catch (Exception e) { var errorMessage = ERROR_MESSAGE_TEMPLATE.formatted(command.getOrder(), command.getId()); @@ -191,4 +124,17 @@ class ArchiveEventListener { currentUserService.resetSecurityContext(prevContext); } } + + private String buildErrorMessage(String message, Exception cause) { + try { + StringBuilder sb = new StringBuilder(message); + if (StringUtils.isNotBlank(cause.getMessage())) { + sb.append(" Cause: ").append(cause.getMessage()); + } + return sb.toString(); + } catch (Exception e2) { + LOG.error("Error in building Error Message (sick).", e2); + return message; + } + } } diff --git a/archive-manager-server/src/main/java/de/ozgcloud/archive/vorgang/ExportVorgangService.java b/archive-manager-server/src/main/java/de/ozgcloud/archive/vorgang/ExportVorgangService.java deleted file mode 100644 index 4e3644613b0233d654d652afae09ef2c69cbaa84..0000000000000000000000000000000000000000 --- a/archive-manager-server/src/main/java/de/ozgcloud/archive/vorgang/ExportVorgangService.java +++ /dev/null @@ -1,58 +0,0 @@ -package de.ozgcloud.archive.vorgang; - -import java.util.Optional; -import java.util.UUID; - -import org.apache.commons.lang3.StringUtils; -import org.springframework.beans.factory.annotation.Qualifier; -import org.springframework.stereotype.Service; - -import de.ozgcloud.archive.ArchiveManagerConfiguration; -import de.xoev.xdomea.AkteType; -import de.xoev.xdomea.AllgemeineMetadatenType; -import de.xoev.xdomea.IdentifikationObjektType; -import de.xoev.xdomea.NkAbgabeType; -import de.xoev.xdomea.VorgangType; -import lombok.RequiredArgsConstructor; - -@RequiredArgsConstructor -@Service -public class ExportVorgangService { - - @Qualifier(ArchiveManagerConfiguration.VORGANG_REMOTE_MANAGER_SERVICE_NAME) // NOSONAR - private final VorgangRemoteService vorgangRemoteService; - - private final VorgangTypeCreator vorgangTypeCreator; - private final KopfCreator kopfCreator; - - public VorgangWithEingang getVorgang(String vorgangId) { - return vorgangRemoteService.findVorgangWithEingang(vorgangId); - } - - public VorgangType createVorgangType(VorgangWithEingang vorgangWithEingang) { - return vorgangTypeCreator.create(vorgangWithEingang); - } - - public NkAbgabeType createKopf(VorgangWithEingang vorgangWithEingang) { - return kopfCreator.createKopf(vorgangWithEingang); - } - - public AkteType createAkteType(VorgangWithEingang vorgangWithEingang) { - var akteType = new AkteType(); - akteType.setIdentifikation(createIdentifikationObjektType()); - akteType.setAllgemeineMetadaten(createAllgemeineMetadatenType(vorgangWithEingang)); - return akteType; - } - - IdentifikationObjektType createIdentifikationObjektType() { - var identifikationObjektType = new IdentifikationObjektType(); - identifikationObjektType.setID(UUID.randomUUID().toString()); - return identifikationObjektType; - } - - AllgemeineMetadatenType createAllgemeineMetadatenType(VorgangWithEingang vorgangWithEingang) { - var allgemeineMetadatenType = new AllgemeineMetadatenType(); - allgemeineMetadatenType.setKennzeichen(Optional.ofNullable(vorgangWithEingang.getAktenzeichen()).orElse(StringUtils.EMPTY)); - return allgemeineMetadatenType; - } -} diff --git a/archive-manager-server/src/main/java/de/ozgcloud/archive/vorgang/VorgangRemoteService.java b/archive-manager-server/src/main/java/de/ozgcloud/archive/vorgang/VorgangRemoteService.java index f78836c848ab2d65bb92f2717a1578421053d224..3ae751e6d9f0131bc611195e49408948d26fc1bb 100644 --- a/archive-manager-server/src/main/java/de/ozgcloud/archive/vorgang/VorgangRemoteService.java +++ b/archive-manager-server/src/main/java/de/ozgcloud/archive/vorgang/VorgangRemoteService.java @@ -1,13 +1,11 @@ package de.ozgcloud.archive.vorgang; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.stereotype.Service; import de.ozgcloud.apilib.common.callcontext.OzgCloudCallContextAttachingInterceptor; import de.ozgcloud.apilib.common.callcontext.OzgCloudCallContextProvider; import de.ozgcloud.archive.ArchiveManagerConfiguration; -import de.ozgcloud.archive.common.GrpcUtil; import de.ozgcloud.vorgang.vorgang.GrpcFindVorgangWithEingangRequest; import de.ozgcloud.vorgang.vorgang.VorgangServiceGrpc.VorgangServiceBlockingStub; import lombok.RequiredArgsConstructor; @@ -17,14 +15,14 @@ import net.devh.boot.grpc.client.inject.GrpcClient; @RequiredArgsConstructor class VorgangRemoteService { - @GrpcClient(GrpcUtil.VORGANG_MANAGER_GRPC_CLIENT) - private VorgangServiceBlockingStub grpcService; - @Autowired + @GrpcClient(ArchiveManagerConfiguration.GRPC_VORGANG_MANAGER_CLIENT_NAME) // NOSONAR + private final VorgangServiceBlockingStub grpcService; + @Qualifier(ArchiveManagerConfiguration.VORGANG_WITH_EINGANG_MAPPER_NAME) // NOSONAR - private VorgangWithEingangMapper vorgangWithEingangMapper; - @Autowired - @Qualifier(ArchiveManagerConfiguration.OZGCLOUD_CALL_CONTEXT_PROVIDER_NAME) - private OzgCloudCallContextProvider contextProvider; + private final VorgangWithEingangMapper vorgangWithEingangMapper; + + @Qualifier(ArchiveManagerConfiguration.CALL_CONTEXT_PROVIDER_NAME) // NOSONAR + private final OzgCloudCallContextProvider contextProvider; public VorgangWithEingang findVorgangWithEingang(String vorgangId) { return vorgangWithEingangMapper diff --git a/archive-manager-server/src/main/java/de/ozgcloud/archive/vorgang/VorgangService.java b/archive-manager-server/src/main/java/de/ozgcloud/archive/vorgang/VorgangService.java new file mode 100644 index 0000000000000000000000000000000000000000..497e0a0d40bb8d7601673e8aaaf2923c2088498e --- /dev/null +++ b/archive-manager-server/src/main/java/de/ozgcloud/archive/vorgang/VorgangService.java @@ -0,0 +1,109 @@ +package de.ozgcloud.archive.vorgang; + +import java.util.Map; +import java.util.Optional; +import java.util.UUID; + +import org.apache.commons.lang3.StringUtils; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.stereotype.Service; + +import de.ozgcloud.apilib.common.command.OzgCloudCommand; +import de.ozgcloud.apilib.common.command.OzgCloudCommandService; +import de.ozgcloud.apilib.common.command.OzgCloudCreateSubCommandsRequest; +import de.ozgcloud.apilib.common.command.grpc.CommandMapper; +import de.ozgcloud.apilib.user.OzgCloudUserId; +import de.ozgcloud.archive.ArchiveManagerConfiguration; +import de.ozgcloud.archive.common.callcontext.CallContextUser; +import de.ozgcloud.archive.common.callcontext.CurrentUserService; +import de.ozgcloud.command.Command; +import de.xoev.xdomea.AkteType; +import de.xoev.xdomea.AllgemeineMetadatenType; +import de.xoev.xdomea.IdentifikationObjektType; +import de.xoev.xdomea.NkAbgabeType; +import de.xoev.xdomea.VorgangType; +import lombok.RequiredArgsConstructor; + +@RequiredArgsConstructor +@Service(ArchiveManagerConfiguration.VORGANG_SERVICE_NAME) // NOSONAR +public class VorgangService { + + static final String LOCK_VORGANG_ORDER = "LOCK_VORGANG"; + static final String KEY_LOCK_VORGANG_REASON = "reason"; + static final String LOCK_VORGANG_REASON = "Vorgang wird archiviert."; + static final String SUB_COMMAND_EXECUTION_MODE = "PARALLEL"; + + @Qualifier(ArchiveManagerConfiguration.VORGANG_REMOTE_MANAGER_SERVICE_NAME) // NOSONAR + private final VorgangRemoteService vorgangRemoteService; + @Qualifier(ArchiveManagerConfiguration.OZGCLOUD_COMMAND_SERVICE_NAME) // NOSONAR + private final OzgCloudCommandService ozgCloudCommandService; + @Qualifier(ArchiveManagerConfiguration.CURRENT_USER_SERVICE_NAME) // NOSONAR + private final CurrentUserService currentUserService; + private final CommandMapper commandMapper; + + private final VorgangTypeCreator vorgangTypeCreator; + private final KopfCreator kopfCreator; + + public VorgangWithEingang getVorgang(String vorgangId) { + return vorgangRemoteService.findVorgangWithEingang(vorgangId); + } + + public VorgangType createVorgangType(VorgangWithEingang vorgangWithEingang) { + return vorgangTypeCreator.create(vorgangWithEingang); + } + + public NkAbgabeType createKopf(VorgangWithEingang vorgangWithEingang) { + return kopfCreator.createKopf(vorgangWithEingang); + } + + public AkteType createAkteType(VorgangWithEingang vorgangWithEingang) { + var akteType = new AkteType(); + akteType.setIdentifikation(createIdentifikationObjektType()); + akteType.setAllgemeineMetadaten(createAllgemeineMetadatenType(vorgangWithEingang)); + return akteType; + } + + IdentifikationObjektType createIdentifikationObjektType() { + var identifikationObjektType = new IdentifikationObjektType(); + identifikationObjektType.setID(UUID.randomUUID().toString()); + return identifikationObjektType; + } + + AllgemeineMetadatenType createAllgemeineMetadatenType(VorgangWithEingang vorgangWithEingang) { + var allgemeineMetadatenType = new AllgemeineMetadatenType(); + allgemeineMetadatenType.setKennzeichen(Optional.ofNullable(vorgangWithEingang.getAktenzeichen()).orElse(StringUtils.EMPTY)); + return allgemeineMetadatenType; + } + + public void lockVorgang(Command command) { + ozgCloudCommandService.addSubCommands(buildCreateSubCommandsRequest(command.getId(), buildLockVorgangSubCommand(command))); + } + + OzgCloudCommand buildLockVorgangSubCommand(Command command) { + var commandBuilder = OzgCloudCommand.builder() + .order(LOCK_VORGANG_ORDER) + .vorgangId(commandMapper.toOzgCloudVorgangId(command.getVorgangId())) + .relationId(commandMapper.mapRelationId(command.getVorgangId())) + .relationVersion(command.getRelationVersion()) + .bodyObject(buildObjectBody()); + getUserId().ifPresent(commandBuilder::createdBy); + return commandBuilder.build(); + } + + Map<String, Object> buildObjectBody() { + return Map.of(KEY_LOCK_VORGANG_REASON, LOCK_VORGANG_REASON); + } + + Optional<OzgCloudUserId> getUserId() { + return currentUserService.findUser().flatMap(CallContextUser::getUserId).map(commandMapper::toOzgCloudUserId); + } + + OzgCloudCreateSubCommandsRequest buildCreateSubCommandsRequest(String parentCommandId, OzgCloudCommand command) { + return OzgCloudCreateSubCommandsRequest.builder() + .parentId(parentCommandId) + .subCommand(command) + .completedIfSubsCompleted(false) + .executionMode(SUB_COMMAND_EXECUTION_MODE) + .build(); + } +} diff --git a/archive-manager-server/src/main/java/de/ozgcloud/archive/xta/XtaService.java b/archive-manager-server/src/main/java/de/ozgcloud/archive/xta/XtaService.java index f1346ebcd1fba179d0ddd5fd2a38a11d92c80e08..59cf635ac808bd3557ba865b923f891148807e20 100644 --- a/archive-manager-server/src/main/java/de/ozgcloud/archive/xta/XtaService.java +++ b/archive-manager-server/src/main/java/de/ozgcloud/archive/xta/XtaService.java @@ -6,6 +6,7 @@ import org.apache.commons.collections.CollectionUtils; import org.springframework.context.ApplicationEventPublisher; import org.springframework.stereotype.Service; +import de.ozgcloud.archive.common.command.ArchiveManagerCommand; import de.ozgcloud.archive.common.command.CommandOrder; import de.ozgcloud.archive.common.command.CommandService; import de.ozgcloud.archive.xta.XtaImportConfirmationHandler.XtaAbgabeHandler; @@ -61,11 +62,11 @@ class XtaService { } } - private List<Command> findPendingArchiveVorgangCommands(String vorgangId) { + private List<ArchiveManagerCommand> findPendingArchiveVorgangCommands(String vorgangId) { return commandService.findPending(vorgangId, CommandOrder.ARCHIVE_VORGANG).toList(); } - void evaluateAbgabe(XtaAbgabeHandler abgabeHandler, List<Command> pendingCommands) { + void evaluateAbgabe(XtaAbgabeHandler abgabeHandler, List<ArchiveManagerCommand> pendingCommands) { if (pendingCommands.size() > 1) { LOG.warn("Multiple pending commands found for vorgang: %s.", abgabeHandler.getVorgangId()); } diff --git a/archive-manager-server/src/test/java/de/ozgcloud/archive/ArchiveTestApplication.java b/archive-manager-server/src/test/java/de/ozgcloud/archive/ArchiveManagerTestApplication.java similarity index 70% rename from archive-manager-server/src/test/java/de/ozgcloud/archive/ArchiveTestApplication.java rename to archive-manager-server/src/test/java/de/ozgcloud/archive/ArchiveManagerTestApplication.java index 68472284ae21c0c15511a344aa57883b719f69d4..5bb43294d647a7e3ae8962348dcd08ebb3fb727e 100644 --- a/archive-manager-server/src/test/java/de/ozgcloud/archive/ArchiveTestApplication.java +++ b/archive-manager-server/src/test/java/de/ozgcloud/archive/ArchiveManagerTestApplication.java @@ -2,30 +2,33 @@ package de.ozgcloud.archive; import java.util.TimeZone; +import org.mapstruct.factory.Mappers; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.info.BuildProperties; import org.springframework.boot.test.mock.mockito.MockBean; import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.ComponentScan; import org.springframework.security.authentication.AuthenticationTrustResolver; import org.springframework.security.authentication.AuthenticationTrustResolverImpl; +import de.ozgcloud.apilib.client_attribute.grpc.OzgCloudClientAttributeMapper; import de.ozgcloud.apilib.common.command.grpc.CommandMapper; -import de.ozgcloud.apilib.common.command.grpc.CommandMapperImpl; import de.ozgcloud.apilib.file.grpc.OzgCloudFileMapper; import de.ozgcloud.apilib.user.UserProfileMapper; import de.ozgcloud.apilib.vorgang.OzgCloudVorgangIdMapper; import de.ozgcloud.apilib.vorgang.grpc.OzgCloudVorgangMapper; -import de.ozgcloud.vorgang.vorgang.VorgangServiceGrpc.VorgangServiceBlockingStub; +import de.ozgcloud.vorgang.vorgang.VorgangServiceGrpc; import de.ozgcloud.xta.client.XtaClient; -@SpringBootApplication(scanBasePackages = { "de.ozgcloud" }) -public class ArchiveTestApplication { +@SpringBootApplication +@ComponentScan({ "de.ozgcloud.*" }) +public class ArchiveManagerTestApplication { @MockBean private OzgCloudVorgangMapper vorgangMapper; @MockBean - private VorgangServiceBlockingStub vorgangServiceStub; + private VorgangServiceGrpc.VorgangServiceBlockingStub vorgangServiceStub; @MockBean private OzgCloudVorgangIdMapper vorgangIdMapper; @MockBean @@ -36,10 +39,12 @@ public class ArchiveTestApplication { private BuildProperties properties; @MockBean private XtaClient xtaClient; + @MockBean + private OzgCloudClientAttributeMapper clientAttributeMapper; public static void main(String[] args) { TimeZone.setDefault(TimeZone.getTimeZone("UTC")); - SpringApplication.run(ArchiveTestApplication.class, args); + SpringApplication.run(ArchiveManagerTestApplication.class, args); } @Bean @@ -49,6 +54,6 @@ public class ArchiveTestApplication { @Bean CommandMapper commandMapper() { - return new CommandMapperImpl(); + return Mappers.getMapper(CommandMapper.class); } } \ No newline at end of file diff --git a/archive-manager-server/src/test/java/de/ozgcloud/archive/common/callcontext/ArchiveCallContextMapperTest.java b/archive-manager-server/src/test/java/de/ozgcloud/archive/common/callcontext/ArchiveCallContextMapperTest.java deleted file mode 100644 index 9f6b7bf30bafe159d441694294509113035ff5c1..0000000000000000000000000000000000000000 --- a/archive-manager-server/src/test/java/de/ozgcloud/archive/common/callcontext/ArchiveCallContextMapperTest.java +++ /dev/null @@ -1,39 +0,0 @@ -package de.ozgcloud.archive.common.callcontext; - -import static org.assertj.core.api.Assertions.*; -import static org.mockito.ArgumentMatchers.*; -import static org.mockito.Mockito.*; - -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Nested; -import org.junit.jupiter.api.Test; -import org.mapstruct.factory.Mappers; -import org.mockito.InjectMocks; -import org.mockito.Mock; - -import de.ozgcloud.archive.common.user.OzgCloudUserIdMapper; - -class ArchiveCallContextMapperTest { - - @InjectMocks - private final ArchiveCallContextMapper mapper = Mappers.getMapper(ArchiveCallContextMapper.class); - - @Mock - private OzgCloudUserIdMapper ozgCloudUserIdMapper; - - @Nested - class TestToOzgCloudCallContext { - - @BeforeEach - void setUpCallToUserIdMapper() { - when(ozgCloudUserIdMapper.fromString(any())).thenCallRealMethod(); - } - - @Test - void shouldMap() { - var mappedContext = mapper.toOzgCloudCallContext(ArchiveCallContextTestFactory.create()); - - assertThat(mappedContext).usingRecursiveComparison().isEqualTo(CallContextTestFactory.create()); - } - } -} diff --git a/archive-manager-server/src/test/java/de/ozgcloud/archive/common/callcontext/ArchiveCallContextTestFactory.java b/archive-manager-server/src/test/java/de/ozgcloud/archive/common/callcontext/ArchiveCallContextTestFactory.java deleted file mode 100644 index 004f98698822d130b8b91a17d0eb99025b04eed7..0000000000000000000000000000000000000000 --- a/archive-manager-server/src/test/java/de/ozgcloud/archive/common/callcontext/ArchiveCallContextTestFactory.java +++ /dev/null @@ -1,42 +0,0 @@ -package de.ozgcloud.archive.common.callcontext; - -import static de.ozgcloud.common.grpc.GrpcUtil.*; - -import java.util.List; -import java.util.UUID; - -import com.thedeanda.lorem.LoremIpsum; - -import de.ozgcloud.archive.common.callcontext.ArchiveCallContext.ArchiveCallContextBuilder; -import io.grpc.Metadata; - -public class ArchiveCallContextTestFactory { - - public static final String REQUEST_ID = UUID.randomUUID().toString(); - public static final String USER_ID = UUID.randomUUID().toString(); - public static final String CLIENT_NAME = LoremIpsum.getInstance().getName(); - public static final List<String> ORGANISATIONS_EINHEITEN_IDS = List.of(UUID.randomUUID().toString()); - public static final Boolean ACCESS_LIMITED = true; - - public static ArchiveCallContext create() { - return createBuilder() - .build(); - } - - public static ArchiveCallContextBuilder createBuilder() { - return ArchiveCallContext.builder() - .requestId(REQUEST_ID) - .clientName(CLIENT_NAME) - .userId(USER_ID) - .accessLimited(ACCESS_LIMITED) - .accessLimitedToOrgaIds(ORGANISATIONS_EINHEITEN_IDS); - } - - public static Metadata createMetadata() { - var metadata = new Metadata(); - metadata.put(createKeyOf(CallContextInterceptor.KEY_ACCESS_LIMITED), ACCESS_LIMITED.toString().getBytes()); - metadata.put(createKeyOf(CallContextInterceptor.KEY_ACCESS_LIMITED_ORGAID), ORGANISATIONS_EINHEITEN_IDS.get(0).getBytes()); - metadata.put(createKeyOf(CallContextInterceptor.KEY_USER_ID), USER_ID.getBytes()); - return metadata; - } -} diff --git a/archive-manager-server/src/test/java/de/ozgcloud/archive/common/callcontext/CallContextGrpcServerInterceptorTest.java b/archive-manager-server/src/test/java/de/ozgcloud/archive/common/callcontext/CallContextGrpcServerInterceptorTest.java new file mode 100644 index 0000000000000000000000000000000000000000..437490ce8620a3f5af6f6b587fae62e2a7e021ad --- /dev/null +++ b/archive-manager-server/src/test/java/de/ozgcloud/archive/common/callcontext/CallContextGrpcServerInterceptorTest.java @@ -0,0 +1,242 @@ +/* + * Copyright (C) 2024 Das Land Schleswig-Holstein vertreten durch den + * Ministerpräsidenten des Landes Schleswig-Holstein + * Staatskanzlei + * Abteilung Digitalisierung und zentrales IT-Management der Landesregierung + * + * 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.archive.common.callcontext; + +import static org.assertj.core.api.Assertions.*; +import static org.mockito.Mockito.*; + +import java.util.Optional; +import java.util.UUID; + +import org.apache.logging.log4j.CloseableThreadContext; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.springframework.test.util.ReflectionTestUtils; + +import de.ozgcloud.common.grpc.GrpcUtil; +import io.grpc.Metadata; +import io.grpc.ServerCall; + +class CallContextGrpcServerInterceptorTest { + + @InjectMocks + private CallContextGrpcServerInterceptor interceptor; + + @Mock + private CurrentUserService currentUserService; + @Mock + private CallContextMapper callContextMapper; + @Mock + private ServerCall.Listener<RequestTest> callListener; + @Mock + private Metadata metadata; + + private CallContextGrpcServerInterceptor.LogContextSettingListener<RequestTest> listener; + + @BeforeEach + void init() { + listener = spy(interceptor.new LogContextSettingListener<>(callListener, metadata)); + } + + @Nested + class TestGetRequestId { + + @Test + void shouldCallGetRequestId() { + try (var grpcUtilMock = mockStatic(GrpcUtil.class)) { + listener.getRequestId(metadata); + + grpcUtilMock.verify(() -> GrpcUtil.getRequestId(metadata)); + } + } + + @Test + void shouldGetRequestIdFromMetadata() { + try (var grpcUtilMock = mockStatic(GrpcUtil.class)) { + var requestId = UUID.randomUUID().toString(); + grpcUtilMock.when(() -> GrpcUtil.getRequestId(any())).thenReturn(Optional.of(requestId)); + + var result = listener.getRequestId(metadata); + + assertThat(result).isEqualTo(requestId); + } + } + + @Test + void shouldReturnGeneratedId() { + try (var grpcUtilMock = mockStatic(GrpcUtil.class)) { + grpcUtilMock.when(() -> GrpcUtil.getRequestId(any())).thenReturn(Optional.empty()); + + var result = listener.getRequestId(metadata); + + assertThat(result).isNotEmpty(); + } + } + } + + @Nested + class TestOnMessage { + + @Test + void shouldCallDoSurroundOn() { + doNothing().when(listener).doSurroundOn(any()); + + listener.onMessage(new RequestTest()); + + verify(listener).doSurroundOn(any()); + } + } + + @Nested + class TestOnHalfClose { + + @Test + void shouldCallDoSurroundOn() { + doNothing().when(listener).doSurroundOn(any()); + + listener.onHalfClose(); + + verify(listener).doSurroundOn(any()); + } + } + + @Nested + class TestOnCancel { + + @Test + void shouldCallDoSurroundOn() { + doNothing().when(listener).doSurroundOn(any()); + + listener.onCancel(); + + verify(listener).doSurroundOn(any()); + } + } + + @Nested + class TestOnComplete { + + @Test + void shouldCallDoSurroundOn() { + doNothing().when(listener).doSurroundOn(any()); + + listener.onComplete(); + + verify(listener).doSurroundOn(any()); + } + } + + @Nested + class TestOnReady { + + @Test + void shouldCallDoSurroundOn() { + doNothing().when(listener).doSurroundOn(any()); + + listener.onReady(); + + verify(listener).doSurroundOn(any()); + } + } + + @Nested + class TestDoSurroundOn { + + @Mock + private Runnable runnable; + + private String requestId; + + @BeforeEach + void init() { + requestId = (String) ReflectionTestUtils.getField(listener, "requestId"); + } + + @Test + void shouldSetThreadContext() { + try (var contextMock = mockStatic(CloseableThreadContext.class)) { + doSurroundOn(); + + contextMock.verify(() -> CloseableThreadContext.put(GrpcUtil.KEY_REQUEST_ID, requestId)); + } + } + + @Test + void shouldCallToCallContextMapper() { + doSurroundOn(); + + verify(callContextMapper).toCallContextUser(metadata, requestId); + } + + @Test + void shouldCallStartSecurityContext() { + var user = CallContextUserTestFactory.create(); + when(callContextMapper.toCallContextUser(any(), any())).thenReturn(user); + + doSurroundOn(); + + verify(currentUserService).startAndReturnPreviousSecurityContext(user); + } + + @Test + void shouldExecuteRunnable() { + doSurroundOn(); + + verify(runnable).run(); + } + + @Test + void shouldResetSecurityContext() { + doSurroundOn(); + + verify(currentUserService).resetSecurityContext(any()); + } + + @Test + void shouldResetSecurityContextOnException() { + doThrow(new RuntimeException()).when(runnable).run(); + + try { + doSurroundOn(); + } catch (RuntimeException e) { + // expected + } + + verify(currentUserService).resetSecurityContext(any()); + } + + private void doSurroundOn() { + listener.doSurroundOn(runnable); + } + } + + private record RequestTest() { + } + + private record ResponseTest() { + } +} \ No newline at end of file diff --git a/archive-manager-server/src/test/java/de/ozgcloud/archive/common/callcontext/CallContextInterceptorTest.java b/archive-manager-server/src/test/java/de/ozgcloud/archive/common/callcontext/CallContextInterceptorTest.java deleted file mode 100644 index 644c95dfbb8a9b4161bf1ce709589240635c9f4b..0000000000000000000000000000000000000000 --- a/archive-manager-server/src/test/java/de/ozgcloud/archive/common/callcontext/CallContextInterceptorTest.java +++ /dev/null @@ -1,122 +0,0 @@ -package de.ozgcloud.archive.common.callcontext; - -import static org.assertj.core.api.Assertions.*; -import static org.mockito.Mockito.*; - -import org.junit.jupiter.api.AfterEach; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Nested; -import org.junit.jupiter.api.Test; -import org.mockito.Mock; -import org.mockito.MockedStatic; -import org.mockito.Spy; - -import io.grpc.Context; -import io.grpc.Contexts; -import io.grpc.Metadata; -import io.grpc.ServerCall; -import io.grpc.ServerCall.Listener; -import io.grpc.ServerCallHandler; - -class CallContextInterceptorTest { - - @Spy - private CallContextInterceptor interceptor; - - @Nested - class TestInterceptCall { - - @Mock - private ServerCall<Object, Object> call; - @Mock - private Metadata headers; - @Mock - private ServerCallHandler<Object, Object> next; - @Mock - private Context grpcContext; - @Mock - private Context newGrpcContext; - @Mock - private Listener<Object> listener; - - private MockedStatic<Context> mockedStaticContext; - - private final ArchiveCallContext archiveCallContext = ArchiveCallContextTestFactory.create(); - - @BeforeEach - void setUpMock() { - doReturn(archiveCallContext).when(interceptor).createArchiveCallContext(headers); - mockedStaticContext = mockStatic(Context.class); - mockedStaticContext.when(Context::current).thenReturn(grpcContext); - when(grpcContext.withValue(CallContextInterceptor.CONTEXT_KEY_CALL_CONTEXT, archiveCallContext)).thenReturn(newGrpcContext); - } - - @AfterEach - void closeMock() { - mockedStaticContext.close(); - } - - @Test - void shouldCreateArchiveCallContext() { - intercept(); - - verify(interceptor).createArchiveCallContext(headers); - } - - @Test - void shouldSetArchiveCallContextInGrpcContext() { - intercept(); - - verify(grpcContext).withValue(CallContextInterceptor.CONTEXT_KEY_CALL_CONTEXT, archiveCallContext); - } - - @Test - void shouldAttachNewGrpcContextToCall() { - try (var mockedStaticContexts = mockStatic(Contexts.class)) { - intercept(); - - mockedStaticContexts.verify(() -> Contexts.interceptCall(newGrpcContext, call, headers, next)); - } - } - - @Test - void shouldReturnListenerWithAttachedGrpcContext() { - try (var mockedStaticContexts = mockStatic(Contexts.class)) { - mockedStaticContexts.when(() -> Contexts.interceptCall(newGrpcContext, call, headers, next)).thenReturn(listener); - - var returnedListener = intercept(); - - assertThat(returnedListener).isEqualTo(listener); - } - } - - private Listener<Object> intercept() { - return interceptor.interceptCall(call, headers, next); - } - } - - @Nested - class TestCreateArchiveCallContext { - - @Test - void shouldCreateArchiveCallContext() { - var archiveCallContext = callInterceptor(); - - assertThat(archiveCallContext).usingRecursiveComparison().ignoringFields("requestId") - .isEqualTo(ArchiveCallContextTestFactory.createBuilder() - .clientName(ArchiveCallContext.CLIENT_NAME) - .build()); - } - - @Test - void shouldHaveRequestId() { - var archiveCallContext = callInterceptor(); - - assertThat(archiveCallContext.getRequestId()).isNotBlank(); - } - - private ArchiveCallContext callInterceptor() { - return interceptor.createArchiveCallContext(ArchiveCallContextTestFactory.createMetadata()); - } - } -} diff --git a/archive-manager-server/src/test/java/de/ozgcloud/archive/common/callcontext/CallContextProviderTest.java b/archive-manager-server/src/test/java/de/ozgcloud/archive/common/callcontext/CallContextProviderTest.java index 6abea45385afc05903fad1155b64e3908e5db0b6..a396a5ea1b771ad31953a07a03b837c195853330 100644 --- a/archive-manager-server/src/test/java/de/ozgcloud/archive/common/callcontext/CallContextProviderTest.java +++ b/archive-manager-server/src/test/java/de/ozgcloud/archive/common/callcontext/CallContextProviderTest.java @@ -19,38 +19,38 @@ class CallContextProviderTest { private CallContextProvider contextProvider; @Mock - private ArchiveCallContextMapper mapper; + private CallContextMapper mapper; @Mock - private GrpcCallContextSupplier contextSupplier; + private CurrentUserService currentUserService; @Nested class TestProvideContext { - private final ArchiveCallContext archiveCallContext = ArchiveCallContextTestFactory.create(); + private final CallContextUser callContextUser = CallContextUserTestFactory.create(); @BeforeEach void mock() { - when(contextSupplier.get()).thenReturn(archiveCallContext); + when(currentUserService.getUser()).thenReturn(callContextUser); } @Test void shouldGetArchiveCallContextFromGrpcContext() { callProvider(); - verify(contextSupplier).get(); + verify(currentUserService).getUser(); } @Test void shouldMapArchiveCallContext() { callProvider(); - verify(mapper).toOzgCloudCallContext(archiveCallContext); + verify(mapper).toOzgCloudCallContext(callContextUser); } @Test void shouldReturnMappedCallContext() { var mappedCallContext = CallContextTestFactory.create(); - when(mapper.toOzgCloudCallContext(archiveCallContext)).thenReturn(mappedCallContext); + when(mapper.toOzgCloudCallContext(callContextUser)).thenReturn(mappedCallContext); var context = callProvider(); diff --git a/archive-manager-server/src/test/java/de/ozgcloud/archive/common/callcontext/CallContextTestFactory.java b/archive-manager-server/src/test/java/de/ozgcloud/archive/common/callcontext/CallContextTestFactory.java index f6886e13340b0efb58c9abc42dff50334b30ccb4..922d37fa72bc5dc45ac97e9f49193cf227d77cbf 100644 --- a/archive-manager-server/src/test/java/de/ozgcloud/archive/common/callcontext/CallContextTestFactory.java +++ b/archive-manager-server/src/test/java/de/ozgcloud/archive/common/callcontext/CallContextTestFactory.java @@ -1,6 +1,6 @@ package de.ozgcloud.archive.common.callcontext; -import java.util.Collection; +import java.util.List; import de.ozgcloud.apilib.common.callcontext.CallContext; import de.ozgcloud.apilib.common.callcontext.CallContext.CallContextBuilder; @@ -8,11 +8,11 @@ import de.ozgcloud.apilib.user.OzgCloudUserId; public class CallContextTestFactory { - public static final String REQUEST_ID = ArchiveCallContextTestFactory.REQUEST_ID; - public static final OzgCloudUserId USER_ID = OzgCloudUserId.from(ArchiveCallContextTestFactory.USER_ID); - public static final String CLIENT_NAME = ArchiveCallContextTestFactory.CLIENT_NAME; - private static final Collection<? extends String> ORGANISATIONS_EINHEITEN_IDS = ArchiveCallContextTestFactory.ORGANISATIONS_EINHEITEN_IDS; - private static final boolean ACCESS_LIMITED = ArchiveCallContextTestFactory.ACCESS_LIMITED; + public static final String REQUEST_ID = CallContextUserTestFactory.REQUEST_ID; + public static final OzgCloudUserId USER_ID = OzgCloudUserId.from(CallContextUserTestFactory.USER_ID); + public static final String CLIENT_NAME = CallContextUserTestFactory.CLIENT_NAME; + public static final String ORGANISATIONS_EINHEITEN_ID = CallContextUserTestFactory.ORGANISATIONS_EINHEITEN_ID; + public static final boolean ACCESS_LIMITED = CallContextUserTestFactory.ACCESS_LIMITED; public static CallContext create() { return createBuilder() @@ -25,6 +25,6 @@ public class CallContextTestFactory { .clientName(CLIENT_NAME) .userId(USER_ID) .accessLimited(ACCESS_LIMITED) - .accessLimitedToOrgaIds(ORGANISATIONS_EINHEITEN_IDS); + .accessLimitedToOrgaIds(List.of(ORGANISATIONS_EINHEITEN_ID)); } } diff --git a/archive-manager-server/src/test/java/de/ozgcloud/archive/common/callcontext/CallContextUserMapperTest.java b/archive-manager-server/src/test/java/de/ozgcloud/archive/common/callcontext/CallContextUserMapperTest.java new file mode 100644 index 0000000000000000000000000000000000000000..5150f31c021c766130b21ecb1386bbb666b030e8 --- /dev/null +++ b/archive-manager-server/src/test/java/de/ozgcloud/archive/common/callcontext/CallContextUserMapperTest.java @@ -0,0 +1,132 @@ +package de.ozgcloud.archive.common.callcontext; + +import static org.assertj.core.api.Assertions.*; +import static org.mockito.ArgumentMatchers.*; +import static org.mockito.Mockito.*; + +import java.util.List; +import java.util.Optional; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; +import org.mapstruct.factory.Mappers; +import org.mockito.InjectMocks; +import org.mockito.Mock; + +import de.ozgcloud.archive.common.user.OzgCloudUserIdMapper; +import de.ozgcloud.common.grpc.GrpcUtil; +import io.grpc.Metadata; + +class CallContextUserMapperTest { + + @InjectMocks + private final CallContextMapper mapper = Mappers.getMapper(CallContextMapper.class); + + @Mock + private OzgCloudUserIdMapper ozgCloudUserIdMapper; + + @Nested + class TestToOzgCloudCallContext { + + @BeforeEach + void setUpCallToUserIdMapper() { + when(ozgCloudUserIdMapper.fromString(any(Optional.class))).thenReturn(CallContextTestFactory.USER_ID); + } + + @Test + void shouldMap() { + var mappedContext = CallContextTestFactory.createBuilder().clientName(CallContextUser.ARCHIVE_MANAGER_CLIENT_NAME).build(); + + var result = mapper.toOzgCloudCallContext(CallContextUserTestFactory.create()); + + assertThat(result).usingRecursiveComparison().isEqualTo(mappedContext); + } + } + + @Nested + class TestToCallContextUser { + + @Mock + private Metadata headers; + + @Test + void shouldMapRequestId() { + var result = toCallContextUser(); + + assertThat(result.getRequestId()).isSameAs(CallContextUserTestFactory.REQUEST_ID); + } + + @Test + void shouldMapClientName() { + try (var grpcUtilMock = mockStatic(GrpcUtil.class)) { + grpcUtilMock.when(() -> GrpcUtil.getClientName(headers)).thenReturn(Optional.of(CallContextUserTestFactory.CLIENT_NAME)); + + var result = toCallContextUser(); + + grpcUtilMock.verify(() -> GrpcUtil.getClientName(headers)); + assertThat(result.getClientName()).isSameAs(CallContextUserTestFactory.CLIENT_NAME); + } + } + + @Test + void shouldMapUserId() { + try (var grpcUtilMock = mockStatic(GrpcUtil.class)) { + grpcUtilMock.when(() -> GrpcUtil.getUserId(headers)).thenReturn(Optional.of(CallContextUserTestFactory.USER_ID)); + + var result = toCallContextUser(); + + grpcUtilMock.verify(() -> GrpcUtil.getUserId(headers)); + assertThat(result.getUserId()).contains(CallContextUserTestFactory.USER_ID); + + } + } + + @Test + void shouldMapUserName() { + try (var grpcUtilMock = mockStatic(GrpcUtil.class)) { + grpcUtilMock.when(() -> GrpcUtil.getUserName(headers)).thenReturn(Optional.of(CallContextUserTestFactory.USER_NAME)); + + var result = toCallContextUser(); + + grpcUtilMock.verify(() -> GrpcUtil.getUserName(headers)); + assertThat(result.getUserName()).contains(CallContextUserTestFactory.USER_NAME); + } + } + + @Test + void shouldMapAccessLimited() { + try (var grpcUtilMock = mockStatic(GrpcUtil.class)) { + grpcUtilMock.when(() -> GrpcUtil.getAccessLimited(headers)).thenReturn(Optional.of(CallContextUserTestFactory.ACCESS_LIMITED)); + grpcUtilMock.when(() -> GrpcUtil.getAccessLimitedOrgaIds(headers)) + .thenReturn(List.of(CallContextUserTestFactory.ORGANISATIONS_EINHEITEN_ID)); + + var result = toCallContextUser(); + + grpcUtilMock.verify(() -> GrpcUtil.getAccessLimited(headers)); + grpcUtilMock.verify(() -> GrpcUtil.getAccessLimitedOrgaIds(headers)); + assertThat(result.isAccessLimited()).isEqualTo(CallContextUserTestFactory.ACCESS_LIMITED); + assertThat(result.getAccessLimitedToOrgaIds()).containsExactly(CallContextUserTestFactory.ORGANISATIONS_EINHEITEN_ID); + } + } + + @Test + void shouldMapNoAccessLimited() { + try (var grpcUtilMock = mockStatic(GrpcUtil.class)) { + grpcUtilMock.when(() -> GrpcUtil.getAccessLimited(any())).thenReturn(Optional.empty()); + grpcUtilMock.when(() -> GrpcUtil.getAccessLimitedOrgaIds(any())) + .thenReturn(List.of(CallContextTestFactory.ORGANISATIONS_EINHEITEN_ID)); + + var result = toCallContextUser(); + + grpcUtilMock.verify(() -> GrpcUtil.getAccessLimited(headers)); + assertThat(result.isAccessLimited()).isFalse(); + assertThat(result.getAccessLimitedToOrgaIds()).isEmpty(); + } + } + + private CallContextUser toCallContextUser() { + return mapper.toCallContextUser(headers, CallContextUserTestFactory.REQUEST_ID); + } + } +} diff --git a/archive-manager-server/src/test/java/de/ozgcloud/archive/common/callcontext/CallContextUserTestFactory.java b/archive-manager-server/src/test/java/de/ozgcloud/archive/common/callcontext/CallContextUserTestFactory.java new file mode 100644 index 0000000000000000000000000000000000000000..f91d32af84e6ac4de855e6e91420ec3675ff08e4 --- /dev/null +++ b/archive-manager-server/src/test/java/de/ozgcloud/archive/common/callcontext/CallContextUserTestFactory.java @@ -0,0 +1,35 @@ +package de.ozgcloud.archive.common.callcontext; + +import java.util.List; +import java.util.Optional; +import java.util.UUID; + +import com.thedeanda.lorem.LoremIpsum; + +import de.ozgcloud.archive.common.callcontext.CallContextUser.CallContextUserBuilder; + +public class CallContextUserTestFactory { + + public static final String REQUEST_ID = UUID.randomUUID().toString(); + public static final String USER_ID = UUID.randomUUID().toString(); + public static final String USER_NAME = LoremIpsum.getInstance().getName(); + public static final String CLIENT_NAME = LoremIpsum.getInstance().getName(); + public static final String ORGANISATIONS_EINHEITEN_ID = UUID.randomUUID().toString(); + public static final Boolean ACCESS_LIMITED = true; + + public static CallContextUser create() { + return createBuilder() + .build(); + } + + public static CallContextUserBuilder createBuilder() { + return CallContextUser.builder() + .requestId(REQUEST_ID) + .clientName(CLIENT_NAME) + .userId(Optional.of(USER_ID)) + .userName(Optional.of(USER_NAME)) + .accessLimited(ACCESS_LIMITED) + .accessLimitedToOrgaIds(List.of(ORGANISATIONS_EINHEITEN_ID)); + } + +} diff --git a/archive-manager-server/src/test/java/de/ozgcloud/archive/common/callcontext/CurrentUserServiceTest.java b/archive-manager-server/src/test/java/de/ozgcloud/archive/common/callcontext/CurrentUserServiceTest.java new file mode 100644 index 0000000000000000000000000000000000000000..2ada38a29b5b6dd1fb78f9655786f6c4b9f727c6 --- /dev/null +++ b/archive-manager-server/src/test/java/de/ozgcloud/archive/common/callcontext/CurrentUserServiceTest.java @@ -0,0 +1,499 @@ +/* + * Copyright (C) 2024 Das Land Schleswig-Holstein vertreten durch den + * Ministerpräsidenten des Landes Schleswig-Holstein + * Staatskanzlei + * Abteilung Digitalisierung und zentrales IT-Management der Landesregierung + * + * 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.archive.common.callcontext; + +import static org.assertj.core.api.AssertionsForClassTypes.*; +import static org.mockito.Mockito.*; + +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.UUID; + +import org.apache.logging.log4j.ThreadContext; +import org.assertj.core.api.InstanceOfAssertFactories; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.MockedStatic; +import org.mockito.Spy; +import org.springframework.security.authentication.AuthenticationTrustResolver; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.GrantedAuthority; +import org.springframework.security.core.context.SecurityContext; +import org.springframework.security.core.context.SecurityContextHolder; + +import de.ozgcloud.command.Command; +import de.ozgcloud.command.CommandTestFactory; +import de.ozgcloud.common.grpc.GrpcUtil; + +class CurrentUserServiceTest { + + @Spy + @InjectMocks + private CurrentUserService service; + + @Mock + private AuthenticationTrustResolver trustResolver; + + @Nested + class TestGetUser { + + @Test + void shouldCallFindUser() { + doReturn(Optional.of(CallContextUserTestFactory.create())).when(service).findUser(); + + service.getUser(); + + verify(service).findUser(); + } + + @Test + void shouldReturnUser() { + var user = CallContextUserTestFactory.create(); + doReturn(Optional.of(user)).when(service).findUser(); + + var result = service.getUser(); + + assertThat(result).isSameAs(user); + } + + @Test + void shouldThrowException() { + doReturn(Optional.empty()).when(service).findUser(); + + assertThatThrownBy(service::getUser).isInstanceOf(IllegalStateException.class); + } + } + + @Nested + class TestFindUser { + + @Mock + private Authentication auth; + + @BeforeEach + void init() { + doReturn(Optional.of(auth)).when(service).findTrustedAuthentication(); + } + + @Test + void shouldCallFindTrustedAuthentication() { + service.findUser(); + + verify(service).findTrustedAuthentication(); + } + + @Test + void shouldCallMapToCallContextUser() { + service.findUser(); + + verify(service).mapToCallContextUser(auth); + } + + @Test + void shouldReturnUser() { + var user = CallContextUserTestFactory.create(); + doReturn(user).when(service).mapToCallContextUser(auth); + + var result = service.findUser(); + + assertThat(result).contains(user); + } + + @Test + void shouldFilterEmptyClientName() { + doReturn(CallContextUserTestFactory.createBuilder().clientName(null).build()).when(service).mapToCallContextUser(auth); + + var result = service.findUser(); + + assertThat(result).isEmpty(); + } + } + + @Nested + class TestMapToCallContextUser { + + @Mock + private Authentication auth; + + @Test + void shouldReturnUser() { + var user = CallContextUserTestFactory.create(); + doReturn(user).when(service).buildDefaultCallContextUser(any()); + + var result = service.mapToCallContextUser(auth); + + assertThat(result).isSameAs(user); + } + + @Test + void shouldCallBuildDefaultCallContextUser() { + service.mapToCallContextUser(auth); + + verify(service).buildDefaultCallContextUser(auth); + } + + @Test + void shouldReturnDefaultUser() { + var user = CallContextUserTestFactory.create(); + doReturn(user).when(service).buildDefaultCallContextUser(auth); + + var result = service.mapToCallContextUser(auth); + + assertThat(result).isSameAs(user); + } + } + + @Nested + class TestBuildDefaultCallContextUser { + + @Mock + private Authentication auth; + @Mock + private GrantedAuthority grantedAuthority; + + @Test + void shouldSetClientName() { + doReturn(CallContextUserTestFactory.CLIENT_NAME).when(auth).getName(); + + var result = service.buildDefaultCallContextUser(auth); + + assertThat(result.getClientName()).isEqualTo(CallContextUserTestFactory.CLIENT_NAME); + } + + @Test + void shouldSetAccessLimited() { + when(grantedAuthority.getAuthority()).thenReturn(CallContextUserTestFactory.ORGANISATIONS_EINHEITEN_ID); + doReturn(List.of(grantedAuthority)).when(auth).getAuthorities(); + + var user = service.buildDefaultCallContextUser(auth); + + assertThat(user.getAccessLimitedToOrgaIds()).asInstanceOf(InstanceOfAssertFactories.LIST) + .containsExactly(CallContextUserTestFactory.ORGANISATIONS_EINHEITEN_ID); + } + + } + + @Nested + class TestFindAuthentication { + + @Mock + private Authentication auth; + + @Test + void shouldCallFindTrustedAuthentication() { + service.findAuthentication(); + + verify(service).findTrustedAuthentication(); + } + + @Test + void shouldReturnAuthentication() { + doReturn(Optional.of(auth)).when(service).findTrustedAuthentication(); + + var result = service.findAuthentication(); + + assertThat(result).contains(auth); + } + } + + @Nested + class TestFindTrustedAuthentication { + + @Mock + private SecurityContext context; + @Mock + private Authentication auth; + + private MockedStatic<SecurityContextHolder> contextHolderMock; + + @BeforeEach + void init() { + contextHolderMock = mockStatic(SecurityContextHolder.class); + contextHolderMock.when(SecurityContextHolder::getContext).thenReturn(context); + when(context.getAuthentication()).thenReturn(auth); + } + + @AfterEach + void cleanup() { + contextHolderMock.close(); + } + + @Test + void shouldCallGetContext() { + service.findTrustedAuthentication(); + + contextHolderMock.verify(SecurityContextHolder::getContext); + } + + @Test + void shouldCallGetAuthentication() { + service.findTrustedAuthentication(); + + verify(context).getAuthentication(); + } + + @Test + void shouldCallIsAnonymous() { + service.findTrustedAuthentication(); + + verify(trustResolver).isAnonymous(auth); + } + + @Test + void shouldCallIsAuthenticated() { + service.findTrustedAuthentication(); + + verify(auth).isAuthenticated(); + } + + @Test + void shouldFilterAnonymous() { + when(trustResolver.isAnonymous(any())).thenReturn(true); + + var result = service.findTrustedAuthentication(); + + assertThat(result).isEmpty(); + verify(auth, never()).isAuthenticated(); + } + + @Test + void shouldFilterNotAuthenticated() { + doReturn(false).when(trustResolver).isAnonymous(auth); + doReturn(false).when(auth).isAuthenticated(); + + var result = service.findTrustedAuthentication(); + + assertThat(result).isEmpty(); + } + } + + @DisplayName("Create user") + @Nested + class TestCreateUser { + + @Test + void shouldSetUserId() { + var user = service.createUser(CommandTestFactory.create()); + + assertThat(user.getUserId()).contains(CommandTestFactory.CREATED_BY); + } + + @Test + void shouldSetUserName() { + var createdByName = "user-name"; + + var user = service.createUser(CommandTestFactory.createBuilder().createdByName(createdByName).build()); + + assertThat(user.getUserName()).contains(createdByName); + } + + @Test + void shouldSetClientName() { + var clientName = "client"; + + var user = service.createUser(CommandTestFactory.createBuilder().createdByClientName(clientName).build()); + + assertThat(user.getClientName()).isEqualTo(clientName); + } + + @Test + void shouldSetAccessLimited() { + var user = service.createUser(CommandTestFactory.create()); + + assertThat(user.isAccessLimited()).isFalse(); + } + + @Test + void shouldCallGetRequestId() { + service.createUser(CommandTestFactory.create()); + + verify(service).getRequestId(); + } + + @Test + void shouldSetRequestId() { + var requestId = UUID.randomUUID().toString(); + doReturn(requestId).when(service).getRequestId(); + + var user = service.createUser(CommandTestFactory.create()); + + assertThat(user.getRequestId()).isEqualTo(requestId); + } + } + + @Nested + class TestGetRequestId { + + @Test + void shouldReturnRequestId() { + var requestId = UUID.randomUUID().toString(); + try (var contextMock = mockStatic(ThreadContext.class)) { + contextMock.when(ThreadContext::getContext).thenReturn(Map.of(GrpcUtil.KEY_REQUEST_ID, requestId)); + + var result = service.getRequestId(); + + assertThat(result).isEqualTo(requestId); + } + } + + @Test + void shouldReturnNewRequestId() { + try (var ctc = mockStatic(ThreadContext.class)) { + ctc.when(ThreadContext::getContext).thenReturn(Collections.emptyMap()); + + var result = service.getRequestId(); + + assertThat(result).isNotEmpty(); + } + } + } + + @Nested + class TestStartAndReturnPreviousSecurityContext { + + @Nested + class TestWithCommand { + + private static final Command COMMAND = CommandTestFactory.create(); + + @Mock + private SecurityContext securityContext; + + @Test + void shouldCallCreateUser() { + startAndReturnPreviousSecurityContext(); + + verify(service).createUser(COMMAND); + } + + @Test + void shouldCallStartAndReturnPreviousSecurityContext() { + var user = CallContextUserTestFactory.create(); + doReturn(user).when(service).createUser(any()); + + startAndReturnPreviousSecurityContext(); + + verify(service).startAndReturnPreviousSecurityContext(user); + } + + @Test + void shouldReturnContext() { + doReturn(securityContext).when(service).startAndReturnPreviousSecurityContext(any(CallContextUser.class)); + + var result = startAndReturnPreviousSecurityContext(); + + assertThat(result).isSameAs(securityContext); + } + + private SecurityContext startAndReturnPreviousSecurityContext() { + return service.startAndReturnPreviousSecurityContext(COMMAND); + } + } + + @Nested + class TestWithCallContextUser { + + private final CallContextUser newUser = CallContextUserTestFactory.create(); + private final CallContextAuthenticationToken newAuthentication = CallContextAuthenticationToken.authenticate(newUser); + + @Mock + private SecurityContext previousSecurityContext; + + @BeforeEach + void init() { + SecurityContextHolder.setContext(previousSecurityContext); + } + + @Test + void shouldReturnPreviousSecurityContext() { + var returnedContext = startAndReturnPreviousSecurityContext(); + + assertThat(returnedContext).isSameAs(previousSecurityContext); + } + + @Test + void shouldSetContextWithNewUser() { + startAndReturnPreviousSecurityContext(); + + var currentAuthentication = SecurityContextHolder.getContext().getAuthentication(); + assertThat(currentAuthentication).usingRecursiveComparison().isEqualTo(newAuthentication); + } + + private SecurityContext startAndReturnPreviousSecurityContext() { + return service.startAndReturnPreviousSecurityContext(newUser); + } + } + } + + @Nested + class TestResetSecurityContext { + + @Mock + private SecurityContext securityContext; + + private MockedStatic<SecurityContextHolder> contextHolderMock; + + @BeforeEach + void init() { + contextHolderMock = mockStatic(SecurityContextHolder.class); + } + + @AfterEach + void cleanup() { + contextHolderMock.close(); + } + + @Test + void shouldClearContext() { + resetSecurityContext(); + + contextHolderMock.verify(SecurityContextHolder::clearContext); + } + + @Test + void shouldSetContext() { + resetSecurityContext(); + + contextHolderMock.verify(() -> SecurityContextHolder.setContext(securityContext)); + } + + @Test + void shouldNotSetContext() { + service.resetSecurityContext(null); + + contextHolderMock.verify(() -> SecurityContextHolder.setContext(any()), never()); + } + + private void resetSecurityContext() { + service.resetSecurityContext(securityContext); + } + } +} \ No newline at end of file diff --git a/archive-manager-server/src/test/java/de/ozgcloud/archive/common/command/CommandServiceTest.java b/archive-manager-server/src/test/java/de/ozgcloud/archive/common/command/CommandServiceTest.java index c6e8b218d22988558b96c559733a3515d98bd5ab..0557c2400baeef93b4e8b0e68deb9cc83e460fc2 100644 --- a/archive-manager-server/src/test/java/de/ozgcloud/archive/common/command/CommandServiceTest.java +++ b/archive-manager-server/src/test/java/de/ozgcloud/archive/common/command/CommandServiceTest.java @@ -4,18 +4,23 @@ import static org.assertj.core.api.Assertions.*; import static org.mockito.ArgumentMatchers.*; import static org.mockito.Mockito.*; +import java.util.Collections; +import java.util.List; import java.util.Optional; import java.util.stream.Stream; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.ValueSource; import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.Spy; +import com.thedeanda.lorem.LoremIpsum; + +import de.ozgcloud.apilib.common.command.OzgCloudCommandService; +import de.ozgcloud.apilib.common.command.grpc.OzgCloudCommandTestFactory; +import de.ozgcloud.apilib.vorgang.OzgCloudVorgangId; import de.ozgcloud.archive.vorgang.VorgangWithEingangTestFactory; import de.ozgcloud.command.CommandStatus; @@ -26,6 +31,8 @@ class CommandServiceTest { private CommandService service; @Mock private CommandRemoteService remoteService; + @Mock + private OzgCloudCommandService ozgCloudCommandService; @Nested class TestFindFinishedCommands { @@ -64,23 +71,48 @@ class CommandServiceTest { } @Nested - class TestHasPendingCommands { + class TestHasPendingCommandsExceptArchive { + + private final String order = LoremIpsum.getInstance().getWords(1); @Test - void shouldCallRemoteService() { - service.hasPendingCommands(VorgangWithEingangTestFactory.ID); + void shouldCallOzgCloudCommandService() { + hasPendingCommandsExceptWithOrder(); - verify(remoteService).hasPendingCommands(VorgangWithEingangTestFactory.ID); + verify(ozgCloudCommandService).getPendingCommands(OzgCloudVorgangId.from(VorgangWithEingangTestFactory.ID)); } - @ParameterizedTest - @ValueSource(booleans = { true, false }) - void shouldReturnRemoteServiceResult(boolean hasPendingCommands) { - when(remoteService.hasPendingCommands(any())).thenReturn(hasPendingCommands); + @Test + void shouldReturnFalseOnNoPendingCommands() { + when(ozgCloudCommandService.getPendingCommands(any())).thenReturn(Collections.emptyList()); - var result = service.hasPendingCommands(VorgangWithEingangTestFactory.ID); + var result = hasPendingCommandsExceptWithOrder(); + + assertThat(result).isFalse(); + } + + @Test + void shouldReturnTrueOnPendingCommands() { + when(ozgCloudCommandService.getPendingCommands(any())).thenReturn(List.of(OzgCloudCommandTestFactory.create())); + + var result = hasPendingCommandsExceptWithOrder(); + + assertThat(result).isTrue(); + } + + @Test + void shouldReturnFalseOnCommandWithExcpetionOrder() { + when(ozgCloudCommandService.getPendingCommands(any())).thenReturn(List.of(OzgCloudCommandTestFactory.createBuilder() + .order(order) + .build())); + + var result = hasPendingCommandsExceptWithOrder(); + + assertThat(result).isFalse(); + } - assertThat(result).isEqualTo(hasPendingCommands); + private boolean hasPendingCommandsExceptWithOrder() { + return service.hasPendingCommandsExceptWithOrder(VorgangWithEingangTestFactory.ID, order); } } } diff --git a/archive-manager-server/src/test/java/de/ozgcloud/archive/common/xta/JsonToXtaIdentifierListConverterTest.java b/archive-manager-server/src/test/java/de/ozgcloud/archive/common/xta/JsonToXtaIdentifierListConverterTest.java new file mode 100644 index 0000000000000000000000000000000000000000..be5d9a974e360c0fdea92a0261e52a7c150553f1 --- /dev/null +++ b/archive-manager-server/src/test/java/de/ozgcloud/archive/common/xta/JsonToXtaIdentifierListConverterTest.java @@ -0,0 +1,48 @@ +package de.ozgcloud.archive.common.xta; + +import static org.assertj.core.api.Assertions.*; +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.ArgumentMatchers.*; +import static org.mockito.Mockito.*; + +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; +import org.mockito.InjectMocks; +import org.mockito.Spy; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.ObjectMapper; + +import de.ozgcloud.common.errorhandling.TechnicalException; +import lombok.SneakyThrows; + +class JsonToXtaIdentifierListConverterTest { + + @InjectMocks + private JsonToXtaIdentifierListConverter converter; + + @Spy + private ObjectMapper objectMapper; + + @Nested + class TestConvert { + + @Test + void shouldReturnListOfXtaIdentifier() { + var jsonInput = XtaIdentifierTestFactory.createAsJson(); + + var identifiers = converter.convert(jsonInput); + + assertThat(identifiers).usingRecursiveFieldByFieldElementComparator().containsExactly(XtaIdentifierTestFactory.create()); + } + + @Test + @SneakyThrows + void shouldThrowTechnicalException() { + doThrow(JsonProcessingException.class).when(objectMapper).readValue(anyString(), any(TypeReference.class)); + + assertThrows(TechnicalException.class, () -> converter.convert("invalid input")); + } + } +} diff --git a/archive-manager-server/src/test/java/de/ozgcloud/archive/common/xta/XtaIdentifierTestFactory.java b/archive-manager-server/src/test/java/de/ozgcloud/archive/common/xta/XtaIdentifierTestFactory.java new file mode 100644 index 0000000000000000000000000000000000000000..35f2f02f7a09728f1293a89fa4c808c44aecdf91 --- /dev/null +++ b/archive-manager-server/src/test/java/de/ozgcloud/archive/common/xta/XtaIdentifierTestFactory.java @@ -0,0 +1,30 @@ +package de.ozgcloud.archive.common.xta; + +import java.util.UUID; + +import com.thedeanda.lorem.LoremIpsum; + +import de.ozgcloud.xta.client.model.XtaIdentifier; +import de.ozgcloud.xta.client.model.XtaIdentifier.XtaIdentifierBuilder; + +public class XtaIdentifierTestFactory { + + public static final String CATEGORY = LoremIpsum.getInstance().getWords(1); + public static final String VALUE = UUID.randomUUID().toString(); + public static final String NAME = LoremIpsum.getInstance().getName(); + + public static XtaIdentifier create() { + return createBuilder().build(); + } + + public static XtaIdentifierBuilder createBuilder() { + return XtaIdentifier.builder() + .name(NAME) + .value(VALUE) + .category(CATEGORY); + } + + public static String createAsJson() { + return "[{\"category\":\"%s\",\"name\":\"%s\",\"value\":\"%s\"}]".formatted(CATEGORY, NAME, VALUE); + } +} diff --git a/archive-manager-server/src/test/java/de/ozgcloud/archive/common/xta/XtaServiceTest.java b/archive-manager-server/src/test/java/de/ozgcloud/archive/common/xta/XtaServiceTest.java new file mode 100644 index 0000000000000000000000000000000000000000..536adb305f6e1acdac5731ff29f1c78eca0fec9a --- /dev/null +++ b/archive-manager-server/src/test/java/de/ozgcloud/archive/common/xta/XtaServiceTest.java @@ -0,0 +1,186 @@ +package de.ozgcloud.archive.common.xta; + +import static org.assertj.core.api.Assertions.*; +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.ArgumentMatchers.*; +import static org.mockito.Mockito.*; + +import java.util.Optional; + +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.MockedStatic; +import org.mockito.Spy; + +import de.ozgcloud.archive.vorgang.XdomeaXtaFileTestFactory; +import de.ozgcloud.common.errorhandling.TechnicalException; +import de.ozgcloud.xta.client.XtaClient; +import de.ozgcloud.xta.client.exception.XtaClientException; +import de.ozgcloud.xta.client.model.XtaFile; +import de.ozgcloud.xta.client.model.XtaMessage; +import de.ozgcloud.xta.client.xdomea.XdomeaXtaMessageCreator; +import lombok.SneakyThrows; + +class XtaServiceTest { + + @Spy + @InjectMocks + private XtaService service; + + @Mock + private XtaClient xtaClient; + + @Nested + class TestSendXdomeaFile { + + private final XtaFile xdomeaFile = XdomeaXtaFileTestFactory.create(); + @Mock + private XtaMessage xtaMessage; + + @BeforeEach + void mock() { + doReturn(xtaMessage).when(service).createMessage(xdomeaFile); + doReturn(xtaClient).when(service).getXtaClient(); + } + + @Test + void shouldGetXtaClient() { + sendXdomeaFile(); + + verify(service).getXtaClient(); + } + + @Test + @SneakyThrows + void shouldCallCreateMessage() { + sendXdomeaFile(); + + verify(service).createMessage(xdomeaFile); + } + + @Test + @SneakyThrows + void shouldSendMessage() { + sendXdomeaFile(); + + verify(xtaClient).sendMessage(xtaMessage); + } + + @Test + @SneakyThrows + void shouldThrowTechnicalException() { + when(xtaClient.sendMessage(any())).thenThrow(XtaClientException.class); + + assertThrows(TechnicalException.class, () -> sendXdomeaFile()); + } + + private void sendXdomeaFile() { + service.sendXdomeaFile(xdomeaFile); + } + } + + @Nested + class TestCreateMessage { + private final XtaFile xdomeaFile = XdomeaXtaFileTestFactory.create(); + + private MockedStatic<XdomeaXtaMessageCreator> mockedStaticXdomeaXtaMessageCreator; + + @Mock + private XdomeaXtaMessageCreator xdomeaXtaMessageCreator; + @Mock + private XtaMessage xtaMessage; + + @BeforeEach + void setUpMock() { + mockedStaticXdomeaXtaMessageCreator = mockStatic(XdomeaXtaMessageCreator.class); + mockedStaticXdomeaXtaMessageCreator.when(XdomeaXtaMessageCreator::createInstance).thenReturn(xdomeaXtaMessageCreator); + } + + @AfterEach + void cleanUp() { + mockedStaticXdomeaXtaMessageCreator.close(); + } + + @Test + void shouldCreateXdomeaXtaMessageCreator() { + createMessage(); + + mockedStaticXdomeaXtaMessageCreator.verify(XdomeaXtaMessageCreator::createInstance); + } + + @Test + @SneakyThrows + void shouldCallCreateMessage() { + createMessage(); + + verify(xdomeaXtaMessageCreator).createMessage(xdomeaFile); + } + + @Test + @SneakyThrows + void shouldReturnMessage() { + when(xdomeaXtaMessageCreator.createMessage(any())).thenReturn(xtaMessage); + + var message = createMessage(); + + assertThat(message).isEqualTo(xtaMessage); + } + + @Test + @SneakyThrows + void shouldThrowTechnicalException() { + when(xdomeaXtaMessageCreator.createMessage(any())).thenThrow(XtaClientException.class); + + assertThrows(TechnicalException.class, () -> createMessage()); + } + + private XtaMessage createMessage() { + return service.createMessage(xdomeaFile); + } + } + + @Nested + class TestGetXtaClient { + + private XtaService xtaService; + + @Nested + class TestOnConfiguredXtaClient { + + @BeforeEach + void givenXtaClientConfigured() { + xtaService = spy(new XtaService(Optional.of(xtaClient))); + } + + @Test + void shouldReturnXtaClient() { + var returnedXtaClient = getXtaClient(); + + assertThat(returnedXtaClient).isSameAs(xtaClient); + } + + } + + @Nested + class TestOnUnconfiguredXtaClient { + + @BeforeEach + void givenXtaClientNotConfigured() { + xtaService = spy(new XtaService(Optional.empty())); + } + + @Test + void shouldThrowTechnicalException() { + assertThrows(TechnicalException.class, () -> getXtaClient()); + } + } + + private XtaClient getXtaClient() { + return xtaService.getXtaClient(); + } + } +} diff --git a/archive-manager-server/src/test/java/de/ozgcloud/archive/export/ExportGrpcServiceITCase.java b/archive-manager-server/src/test/java/de/ozgcloud/archive/export/ExportGrpcServiceITCase.java index fdb7e30c7fa8a9f216817307d148ed912f8d62b2..f31301a2b63230bcbc807b08606340d4f9bc0656 100644 --- a/archive-manager-server/src/test/java/de/ozgcloud/archive/export/ExportGrpcServiceITCase.java +++ b/archive-manager-server/src/test/java/de/ozgcloud/archive/export/ExportGrpcServiceITCase.java @@ -17,7 +17,6 @@ import java.util.zip.ZipInputStream; import org.apache.commons.io.IOUtils; import org.apache.commons.lang3.StringUtils; import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; import org.springframework.boot.test.context.SpringBootTest; @@ -42,7 +41,7 @@ import de.ozgcloud.archive.kommentar.KommentarsExportData; import de.ozgcloud.archive.kommentar.KommentarsExportDataTestFactory; import de.ozgcloud.archive.postfach.ExportNachrichtService; import de.ozgcloud.archive.postfach.PostfachMailExportData; -import de.ozgcloud.archive.vorgang.ExportVorgangService; +import de.ozgcloud.archive.vorgang.VorgangService; import de.ozgcloud.archive.vorgang.VorgangTypeTestFactory; import de.ozgcloud.archive.vorgang.VorgangWithEingang; import de.ozgcloud.archive.vorgang.VorgangWithEingangTestFactory; @@ -54,7 +53,6 @@ import net.devh.boot.grpc.client.inject.GrpcClient; "grpc.server.inProcessName=GrpcExportService-test", "grpc.client.inProcess.address=in-process:GrpcExportService-test" }) -// @SpringJUnitConfig(classes = { GrpcIntegrationTestConfiguration.class }) @ITCase @DirtiesContext class ExportGrpcServiceITCase { @@ -65,7 +63,7 @@ class ExportGrpcServiceITCase { @MockBean private ExportFileService exportFileService; @MockBean - private ExportVorgangService exportVorgangService; + private VorgangService vorgangService; @MockBean private ExportHistorieService exportHistorieService; @MockBean @@ -87,20 +85,20 @@ class ExportGrpcServiceITCase { @BeforeEach void setUpCommonMocks() { - when(exportVorgangService.getVorgang(VorgangWithEingangTestFactory.ID)).thenReturn(vorgang); + when(vorgangService.getVorgang(VorgangWithEingangTestFactory.ID)).thenReturn(vorgang); when(exportNachrichtService.createExportData(vorgang)).thenReturn(PostfachMailExportData.builder().build()); when(exportBescheidService.createExportData(vorgang)).thenReturn(BescheidExportData.builder().build()); when(exportFileService.getRepresentations(vorgang)).thenReturn(Stream.empty()); when(exportFileService.getAttachments(vorgang)).thenReturn(Stream.empty()); - when(exportVorgangService.createKopf(vorgang)).thenReturn(NkAbgabeTypeTestFactory.create()); - when(exportVorgangService.createVorgangType(vorgang)).thenReturn(VorgangTypeTestFactory.create()); - when(exportVorgangService.createAkteType(vorgang)).thenReturn(AkteTypeTestFactory.create()); + when(vorgangService.createKopf(vorgang)).thenReturn(NkAbgabeTypeTestFactory.create()); + when(vorgangService.createVorgangType(vorgang)).thenReturn(VorgangTypeTestFactory.create()); + when(vorgangService.createAkteType(vorgang)).thenReturn(AkteTypeTestFactory.create()); } @Nested - class OnMinimalVorgang { + class TestOnMinimalVorgang { @BeforeEach void setUpMock() { @@ -121,7 +119,6 @@ class ExportGrpcServiceITCase { assertThat(numEntry).isEqualTo(1); } - @Disabled("FIXME: Führt man die ganze Klasse aus bleibt er beim zweiten Test hängen. Führt man die Tests einzelnd aus funktionieren sie.") @Test @SneakyThrows void shouldContainVorgangKopfDataInXml() { @@ -137,9 +134,8 @@ class ExportGrpcServiceITCase { } } - @Disabled("FIXME: Führt man die ganze Klasse aus bleibt er beim zweiten Test hängen. Führt man die Tests einzelnd aus funktionieren sie.") @Nested - class OnVorgangWithKommentarAndAttachment { + class TestOnVorgangWithKommentarAndAttachment { private final String attachmentContent = LoremIpsum.getInstance().getWords(5); @BeforeEach diff --git a/archive-manager-server/src/test/java/de/ozgcloud/archive/export/ExportServiceITCase.java b/archive-manager-server/src/test/java/de/ozgcloud/archive/export/ExportServiceITCase.java index d085f3d41f19d41bcaa323dbe984f95cebb739f0..74b813c3d8ecb10ffd58e0dde14d1f25e818f977 100644 --- a/archive-manager-server/src/test/java/de/ozgcloud/archive/export/ExportServiceITCase.java +++ b/archive-manager-server/src/test/java/de/ozgcloud/archive/export/ExportServiceITCase.java @@ -30,7 +30,7 @@ import de.ozgcloud.archive.postfach.ExportNachrichtService; import de.ozgcloud.archive.postfach.PostfachMail; import de.ozgcloud.archive.postfach.PostfachMailExportDataTestFactory; import de.ozgcloud.archive.postfach.PostfachMailTestFactory; -import de.ozgcloud.archive.vorgang.ExportVorgangService; +import de.ozgcloud.archive.vorgang.VorgangService; import de.ozgcloud.archive.vorgang.VorgangWithEingang; import de.ozgcloud.archive.vorgang.VorgangWithEingangTestFactory; import de.ozgcloud.common.test.ITCase; @@ -41,7 +41,7 @@ class ExportServiceITCase { @SpyBean private ExportFileService exportFileService; @SpyBean - private ExportVorgangService exportVorgangService; + private VorgangService vorgangService; @MockBean private ExportHistorieService exportHistorieService; @MockBean @@ -66,7 +66,7 @@ class ExportServiceITCase { @BeforeEach void setup() { - doReturn(vorgang).when(exportVorgangService).getVorgang(VorgangWithEingangTestFactory.ID); + doReturn(vorgang).when(vorgangService).getVorgang(VorgangWithEingangTestFactory.ID); doReturn(Stream.of(OzgFileTestFactory.createWithUniqueId())).when(exportFileService).getRepresentations(vorgang); doReturn(Stream.of(OzgFileTestFactory.createWithUniqueId())).when(exportFileService).getAttachments(vorgang); doReturn(Stream.of(OzgFileTestFactory.createWithUniqueId())).when(binaryFileService).getFiles(postfachMail.getAttachments()); diff --git a/archive-manager-server/src/test/java/de/ozgcloud/archive/export/ExportServiceTest.java b/archive-manager-server/src/test/java/de/ozgcloud/archive/export/ExportServiceTest.java index 66e566632917007778f2eebe719f019f7b9971dd..128073afea1917cf3b050fd3cff99ce6e1e5fb3e 100644 --- a/archive-manager-server/src/test/java/de/ozgcloud/archive/export/ExportServiceTest.java +++ b/archive-manager-server/src/test/java/de/ozgcloud/archive/export/ExportServiceTest.java @@ -2,9 +2,11 @@ package de.ozgcloud.archive.export; import static de.ozgcloud.archive.common.XDomeaTestUtils.*; import static org.assertj.core.api.Assertions.*; +import static org.junit.jupiter.api.Assertions.*; import static org.mockito.ArgumentMatchers.*; import static org.mockito.Mockito.*; +import java.io.File; import java.io.IOException; import java.io.OutputStream; import java.nio.charset.StandardCharsets; @@ -13,6 +15,9 @@ import java.util.UUID; import java.util.zip.ZipEntry; import java.util.zip.ZipOutputStream; +import jakarta.activation.DataHandler; +import jakarta.activation.FileDataSource; + import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayName; @@ -22,6 +27,7 @@ import org.mockito.ArgumentCaptor; import org.mockito.Captor; import org.mockito.InjectMocks; import org.mockito.Mock; +import org.mockito.MockedConstruction; import org.mockito.MockedStatic; import org.mockito.Spy; @@ -31,6 +37,7 @@ import de.ozgcloud.archive.bescheid.ExportBescheidService; import de.ozgcloud.archive.common.ExportFilenameGenerator; import de.ozgcloud.archive.common.HistorienProtokollInformationTypeTestFactory; import de.ozgcloud.archive.common.XDomeaTestUtils; +import de.ozgcloud.archive.common.xta.XtaService; import de.ozgcloud.archive.file.ExportFileService; import de.ozgcloud.archive.file.OzgFile; import de.ozgcloud.archive.file.OzgFileTestFactory; @@ -43,11 +50,15 @@ import de.ozgcloud.archive.postfach.PostfachMailExportData; import de.ozgcloud.archive.postfach.PostfachMailExportDataTestFactory; import de.ozgcloud.archive.vorgang.EingangHeaderTestFactory; import de.ozgcloud.archive.vorgang.EingangTestFactory; -import de.ozgcloud.archive.vorgang.ExportVorgangService; +import de.ozgcloud.archive.vorgang.VorgangService; import de.ozgcloud.archive.vorgang.VorgangTypeTestFactory; import de.ozgcloud.archive.vorgang.VorgangWithEingang; import de.ozgcloud.archive.vorgang.VorgangWithEingangTestFactory; +import de.ozgcloud.archive.vorgang.XdomeaXtaFileTestFactory; +import de.ozgcloud.command.Command; +import de.ozgcloud.command.CommandTestFactory; import de.ozgcloud.common.errorhandling.TechnicalException; +import de.ozgcloud.xta.client.model.XtaFile; import de.xoev.xdomea.AbgabeAbgabe0401; import de.xoev.xdomea.AkteType; import de.xoev.xdomea.DokumentType; @@ -68,7 +79,7 @@ class ExportServiceTest { @Mock private ExportFileService exportFileService; @Mock - private ExportVorgangService exportVorgangService; + private VorgangService vorgangService; @Mock private ExportHistorieService exportHistorieService; @Mock @@ -77,6 +88,8 @@ class ExportServiceTest { private ExportNachrichtService exportNachrichtService; @Mock private ExportBescheidService exportBescheidService; + @Mock + private XtaService xtaService; @DisplayName("Write Xdomea File") @Nested @@ -155,10 +168,10 @@ class ExportServiceTest { } private void setUpVorgangService() { - when(exportVorgangService.getVorgang(VorgangWithEingangTestFactory.ID)).thenReturn(vorgang); - when(exportVorgangService.createVorgangType(vorgang)).thenReturn(vorgangType); - when(exportVorgangService.createKopf(vorgang)).thenReturn(kopfType); - when(exportVorgangService.createAkteType(vorgang)).thenReturn(akteType); + when(vorgangService.getVorgang(VorgangWithEingangTestFactory.ID)).thenReturn(vorgang); + when(vorgangService.createVorgangType(vorgang)).thenReturn(vorgangType); + when(vorgangService.createKopf(vorgang)).thenReturn(kopfType); + when(vorgangService.createAkteType(vorgang)).thenReturn(akteType); } private void setUpXdomeaNachrichtBuilder() { @@ -213,7 +226,7 @@ class ExportServiceTest { void shouldLoadVorgang() { callService(); - verify(exportVorgangService).getVorgang(VorgangWithEingangTestFactory.ID); + verify(vorgangService).getVorgang(VorgangWithEingangTestFactory.ID); } @Test @@ -241,14 +254,14 @@ class ExportServiceTest { void shouldCreateKopf() { callService(); - verify(exportVorgangService).createKopf(vorgang); + verify(vorgangService).createKopf(vorgang); } @Test void shouldCreateVorgangType() { callService(); - verify(exportVorgangService).createVorgangType(vorgang); + verify(vorgangService).createVorgangType(vorgang); } @Test @@ -276,7 +289,7 @@ class ExportServiceTest { void shouldCreateAkteType() { callService(); - verify(exportVorgangService).createAkteType(vorgang); + verify(vorgangService).createAkteType(vorgang); } @Test @@ -655,4 +668,216 @@ class ExportServiceTest { assertThat(fileName).isEqualTo(id + "_Abgabe.Abgabe.0401.xdomea"); } } + + @Nested + class TestArchiveVorgang { + + private final Command command = CommandTestFactory.create(); + private final XtaFile xdomeaFile = XdomeaXtaFileTestFactory.create(); + + @BeforeEach + void mock() { + doReturn(xdomeaFile).when(service).buildXdomeaXtaFile(CommandTestFactory.VORGANG_ID); + } + + @Test + void shouldCallBuildXdomeaXtaFile() { + archiveVorgang(); + + verify(service).buildXdomeaXtaFile(CommandTestFactory.VORGANG_ID); + } + + @Test + void shouldCallSendXdomeaFile() { + archiveVorgang(); + + verify(xtaService).sendXdomeaFile(xdomeaFile); + } + + private void archiveVorgang() { + service.archiveVorgang(command); + } + } + + @Nested + class TestBuildXdomeaXtaFile { + + private final String fileNameId = UUID.randomUUID().toString(); + + @BeforeEach + void mock() { + doReturn(fileNameId).when(service).createFileNameId(); + doReturn(XdomeaXtaFileTestFactory.FILE_NAME).when(service).buildXdomeaFileName(any()); + doReturn(XdomeaXtaFileTestFactory.DATA_HANDLER).when(service).createFileContent(VorgangWithEingangTestFactory.ID, fileNameId); + } + + @Test + void shouldCallCreateFileNameId() { + buildXdomeaXtaFile(); + + verify(service).createFileNameId(); + } + + @Test + void shouldCallBuildXdomeaFileName() { + buildXdomeaXtaFile(); + + verify(service).buildXdomeaFileName(fileNameId); + } + + @Test + void shouldCallCreateFileContent() { + buildXdomeaXtaFile(); + + verify(service).createFileContent(VorgangWithEingangTestFactory.ID, fileNameId); + } + + @Test + void shouldReturnXdomeaFile() { + var xdomeaFile = buildXdomeaXtaFile(); + + assertThat(xdomeaFile).usingRecursiveComparison().isEqualTo(XdomeaXtaFileTestFactory.create()); + } + + private XtaFile buildXdomeaXtaFile() { + return service.buildXdomeaXtaFile(VorgangWithEingangTestFactory.ID); + } + } + + @Nested + class TestCreateFileNameId { + + private final UUID uuid = UUID.randomUUID(); + + @Test + void shouldReturnRandomUUID() { + try (var mockedStaticUUID = mockStatic(UUID.class)) { + mockedStaticUUID.when(UUID::randomUUID).thenReturn(uuid); + + var returnedFileNameId = service.createFileNameId(); + + assertThat(returnedFileNameId).isEqualTo(uuid.toString()); + } + } + } + + @Nested + class TestCreateFileContent { + + private final String fileNameId = UUID.randomUUID().toString(); + + @Nested + class TestOnNoExceptionThrown { + private MockedConstruction<FileDataSource> fileDataSourceConstruction; + private FileDataSource fileDataSource; + private File dataSourceFile; + + private MockedConstruction<DataHandler> dataHandlerConstruction; + private DataHandler dataHandler; + private FileDataSource dataHandlerSource; + + @Mock + private File tempFile; + @Mock + private OutputStream outputStream; + + @BeforeEach + @SneakyThrows + void setUpMock() { + doReturn(tempFile).when(service).createTempFile(fileNameId); + fileDataSourceConstruction = mockConstruction(FileDataSource.class, + (fileDataSource, context) -> { + dataSourceFile = (File) context.arguments().get(0); + this.fileDataSource = fileDataSource; + when(fileDataSource.getOutputStream()).thenReturn(outputStream); + }); + dataHandlerConstruction = mockConstruction(DataHandler.class, (dataHandler, context) -> { + this.dataHandler = dataHandler; + dataHandlerSource = (FileDataSource) context.arguments().get(0); + }); + doNothing().when(service).writeXdomeaFileContent(any(), any(), any()); + } + + @AfterEach + void cleanUp() { + fileDataSourceConstruction.close(); + dataHandlerConstruction.close(); + } + + @Test + @SneakyThrows + void shouldCallCreateTempFile() { + createFileContent(); + + verify(service).createTempFile(fileNameId); + } + + @Test + void shouldCreateFileDataSourceWithTempFile() { + createFileContent(); + + assertThat(dataSourceFile).isEqualTo(tempFile); + } + + @Test + @SneakyThrows + void shouldGetOutputStreamOfFileDataSource() { + createFileContent(); + + verify(fileDataSource).getOutputStream(); + } + + @Test + void shouldWriteXdomeaContentToOutputStream() { + createFileContent(); + + verify(service).writeXdomeaFileContent(VorgangWithEingangTestFactory.ID, fileNameId, outputStream); + } + + @Test + void shouldConstructDataHandlerFromFileDataSource() { + createFileContent(); + + assertThat(dataHandlerConstruction.constructed()).hasSize(1); + assertThat(dataHandlerSource).isEqualTo(fileDataSource); + } + + @Test + void shouldReturnDataHandler() { + var resultDataHandler = createFileContent(); + + assertThat(resultDataHandler).isEqualTo(dataHandler); + } + } + + @Nested + class TestOnIOExceptionThrown { + @Test + @SneakyThrows + void shouldThrowTechnicalExcpetion() { + doThrow(IOException.class).when(service).createTempFile(any()); + + assertThrows(TechnicalException.class, () -> createFileContent()); + } + } + + private DataHandler createFileContent() { + return service.createFileContent(VorgangWithEingangTestFactory.ID, fileNameId); + } + } + + @Nested + class TestCreateTempFile { + + private final String fileNameId = UUID.randomUUID().toString(); + + @Test + @SneakyThrows + void shouldReturnFile() { + var file = service.createTempFile(fileNameId); + + assertThat(file).isNotNull().isInstanceOf(File.class); + } + } + } \ No newline at end of file diff --git a/archive-manager-server/src/test/java/de/ozgcloud/archive/export/XdomeaPropertiesValidatorTest.java b/archive-manager-server/src/test/java/de/ozgcloud/archive/export/XdomeaPropertiesValidatorTest.java index d8db5aefb82097daee33e8f0178763e30f4deee6..f68a18eaf38ccbb1f9b7f90821f03000da54652d 100644 --- a/archive-manager-server/src/test/java/de/ozgcloud/archive/export/XdomeaPropertiesValidatorTest.java +++ b/archive-manager-server/src/test/java/de/ozgcloud/archive/export/XdomeaPropertiesValidatorTest.java @@ -48,7 +48,7 @@ class XdomeaPropertiesValidatorTest { } @Nested - class OnUriNotSet { + class TestOnUriNotSet { private static final String PROPERTY_NAME = "behoerdenschluesselUri"; public static final String PROPERTY_PATH = "ozgcloud.xdomea." + PROPERTY_NAME; @@ -90,7 +90,7 @@ class XdomeaPropertiesValidatorTest { } @Nested - class OnVersionNotSet { + class TestOnVersionNotSet { public static final String PROPERTY_NAME = "behoerdenschluesselVersion"; public static final String PROPERTY_PATH = "ozgcloud.xdomea." + PROPERTY_NAME; diff --git a/archive-manager-server/src/test/java/de/ozgcloud/archive/postfach/PostfachMailMapperTest.java b/archive-manager-server/src/test/java/de/ozgcloud/archive/postfach/PostfachMailMapperTest.java index 4abe1b673302a6398edd3a4af254e09c39f0c00b..3896fce98519be071d6695e0df8ff4f389e68b79 100644 --- a/archive-manager-server/src/test/java/de/ozgcloud/archive/postfach/PostfachMailMapperTest.java +++ b/archive-manager-server/src/test/java/de/ozgcloud/archive/postfach/PostfachMailMapperTest.java @@ -26,6 +26,7 @@ package de.ozgcloud.archive.postfach; import static org.assertj.core.api.Assertions.*; import static org.mockito.Mockito.*; +import org.apache.commons.lang3.StringUtils; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; @@ -73,6 +74,13 @@ class PostfachMailMapperTest { assertThat(postfachMail).usingRecursiveComparison().isEqualTo(PostfachMailTestFactory.create()); } + @Test + void shouldMapEmptyCreatedByToNull() { + var postfachMail = mapper.toPostfachMail(GrpcPostfachMailTestFactory.createBuilder().setCreatedBy(StringUtils.EMPTY).build()); + + assertThat(postfachMail.getCreatedBy()).isNull(); + } + private PostfachMail toPostfachMail() { return mapper.toPostfachMail(GrpcPostfachMailTestFactory.create()); } diff --git a/archive-manager-server/src/test/java/de/ozgcloud/archive/vorgang/ArchiveEventListenerITCase.java b/archive-manager-server/src/test/java/de/ozgcloud/archive/vorgang/ArchiveEventListenerITCase.java index 10e044811390c0f84e272c069aea7a4718ccf1bd..e72c6347f66a6c5e27cf33583a37198bcb84a71a 100644 --- a/archive-manager-server/src/test/java/de/ozgcloud/archive/vorgang/ArchiveEventListenerITCase.java +++ b/archive-manager-server/src/test/java/de/ozgcloud/archive/vorgang/ArchiveEventListenerITCase.java @@ -50,12 +50,11 @@ class ArchiveEventListenerITCase { @Nested class TestOnArchiveVorgang { - private static final Command command = CommandTestFactory.createBuilder().order(ArchiveEventListener.ARCHIVE_VORGANG_ORDER) - .build(); + private static final Command COMMAND = CommandTestFactory.createBuilder().order(ArchiveEventListener.ARCHIVE_VORGANG_ORDER).build(); @Test void shouldReactOnOrder() { - var event = CommandCreatedEventTestFactory.withCommand(command); + var event = CommandCreatedEventTestFactory.withCommand(COMMAND); publisher.publishEvent(event); diff --git a/archive-manager-server/src/test/java/de/ozgcloud/archive/vorgang/ArchiveEventListenerTest.java b/archive-manager-server/src/test/java/de/ozgcloud/archive/vorgang/ArchiveEventListenerTest.java index b25f1abd967ffbdd254a84f7b0c934c9081281cc..8f0318b145df6c6ea3b7fafbb73a5bafb74ae6dc 100644 --- a/archive-manager-server/src/test/java/de/ozgcloud/archive/vorgang/ArchiveEventListenerTest.java +++ b/archive-manager-server/src/test/java/de/ozgcloud/archive/vorgang/ArchiveEventListenerTest.java @@ -24,32 +24,23 @@ package de.ozgcloud.archive.vorgang; import static org.assertj.core.api.Assertions.*; -import static org.junit.jupiter.api.Assertions.*; import static org.mockito.ArgumentMatchers.*; import static org.mockito.Mockito.*; -import java.io.File; -import java.io.IOException; -import java.io.OutputStream; -import java.util.Optional; -import java.util.UUID; import java.util.function.Consumer; -import jakarta.activation.DataHandler; -import jakarta.activation.FileDataSource; - -import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; import org.mockito.ArgumentCaptor; import org.mockito.Captor; +import org.mockito.InjectMocks; import org.mockito.Mock; -import org.mockito.MockedConstruction; -import org.mockito.MockedStatic; +import org.mockito.Spy; import org.springframework.context.ApplicationEventPublisher; import org.springframework.security.core.context.SecurityContext; +import de.ozgcloud.archive.attributes.ClientAttributeService; import de.ozgcloud.archive.common.callcontext.CurrentUserService; import de.ozgcloud.archive.common.command.CommandService; import de.ozgcloud.archive.common.errorhandling.TimeoutException; @@ -59,84 +50,76 @@ import de.ozgcloud.command.CommandCreatedEventTestFactory; import de.ozgcloud.command.CommandFailedEvent; import de.ozgcloud.command.CommandTestFactory; import de.ozgcloud.command.VorgangLockedEvent; -import de.ozgcloud.common.errorhandling.TechnicalException; -import de.ozgcloud.xta.client.XtaClient; -import de.ozgcloud.xta.client.exception.XtaClientException; -import de.ozgcloud.xta.client.model.XtaFile; -import de.ozgcloud.xta.client.model.XtaMessage; -import de.ozgcloud.xta.client.xdomea.XdomeaXtaMessageCreator; -import lombok.SneakyThrows; class ArchiveEventListenerTest { + private static final Command COMMAND = CommandTestFactory.create(); + + @Spy + @InjectMocks private ArchiveEventListener eventListener; @Mock private CurrentUserService currentUserService; @Mock - private ApplicationEventPublisher eventPublisher; + private ClientAttributeService clientAttributeService; @Mock - private ExportService exportService; + private VorgangService vorgangService; @Mock - private XtaClient xtaClient; + private ApplicationEventPublisher eventPublisher; @Mock private CommandService commandService; + @Mock + private ExportService exportService; @Captor private ArgumentCaptor<Consumer<Command>> commandExecutorCapture; - @BeforeEach - void setUp() { - eventListener = spy(new ArchiveEventListener(currentUserService, eventPublisher, exportService, Optional.of(xtaClient), commandService)); - } - @Nested class TestOnArchiveEvent { - private static final Command COMMAND = CommandTestFactory.create(); - @BeforeEach void init() { - doNothing().when(eventListener).doArchiveVorgang(any()); + doNothing().when(eventListener).doLockVorgang(any()); } @Test void shouldCallRunWithSecurityContext() { - eventListener.onArchiveVorgangEvent(CommandCreatedEventTestFactory.withCommand(COMMAND)); + doNothing().when(eventListener).runWithSecurityContext(any(), any()); - verify(eventListener).runWithSecurityContext(eq(COMMAND), any()); - } - - @Test - void shouldCallDoArchiveVorgang() { eventListener.onArchiveVorgangEvent(CommandCreatedEventTestFactory.withCommand(COMMAND)); - verify(eventListener).doArchiveVorgang(COMMAND); + verify(eventListener).runWithSecurityContext(eq(COMMAND), commandExecutorCapture.capture()); + commandExecutorCapture.getValue().accept(COMMAND); + verify(eventListener).doLockVorgang(COMMAND); } } @Nested - class TestDoArchiveVorgang { + class TestDoLockVorgang { - private static final Command COMMAND = CommandTestFactory.create(); + @Test + void shouldCallSetVorgangArchiving() { + doLockVorgang(); + + verify(clientAttributeService).setVorgangArchiving(CommandTestFactory.VORGANG_ID); + } @Test - void shouldLogArchivingVorgang() { - doArchiveVorgang(); + void shouldCallLockVorgang() { + doLockVorgang(); - verify(eventListener).doArchiveVorgang(COMMAND); + verify(vorgangService).lockVorgang(COMMAND); } - private void doArchiveVorgang() { - eventListener.doArchiveVorgang(COMMAND); + private void doLockVorgang() { + eventListener.doLockVorgang(COMMAND); } } @Nested class TestRunWithSecurityContext { - private final Command command = CommandTestFactory.createBuilder().build(); - @Mock private Consumer<Command> commandExecutor; @Mock @@ -146,26 +129,26 @@ class ArchiveEventListenerTest { @BeforeEach void init() { - when(currentUserService.startSecurityContext(any())).thenReturn(secContext); + when(currentUserService.startAndReturnPreviousSecurityContext(any(Command.class))).thenReturn(secContext); } @Test void shouldStartSecurityContext() { - eventListener.runWithSecurityContext(command, commandExecutor); + eventListener.runWithSecurityContext(COMMAND, commandExecutor); - verify(currentUserService).startSecurityContext(command); + verify(currentUserService).startAndReturnPreviousSecurityContext(COMMAND); } @Test void shouldExecuteCommand() { - eventListener.runWithSecurityContext(command, commandExecutor); + eventListener.runWithSecurityContext(COMMAND, commandExecutor); - verify(commandExecutor).accept(command); + verify(commandExecutor).accept(COMMAND); } @Test void shouldResetSecurityContext() { - eventListener.runWithSecurityContext(command, commandExecutor); + eventListener.runWithSecurityContext(COMMAND, commandExecutor); verify(currentUserService).resetSecurityContext(secContext); } @@ -174,7 +157,7 @@ class ArchiveEventListenerTest { void shouldResetSecurityContextAfterException() { doThrow(new RuntimeException("ups")).when(commandExecutor).accept(any()); - eventListener.runWithSecurityContext(command, commandExecutor); + eventListener.runWithSecurityContext(COMMAND, commandExecutor); verify(currentUserService).resetSecurityContext(secContext); } @@ -183,10 +166,10 @@ class ArchiveEventListenerTest { void shouldPublishCommandFailedEvent() { doThrow(new RuntimeException("ups")).when(commandExecutor).accept(any()); - eventListener.runWithSecurityContext(command, commandExecutor); + eventListener.runWithSecurityContext(COMMAND, commandExecutor); verify(eventPublisher).publishEvent(commandFailedEventCaptor.capture()); - assertThat(commandFailedEventCaptor.getValue().getSource()).isEqualTo(command.getId()); + assertThat(commandFailedEventCaptor.getValue().getSource()).isEqualTo(CommandTestFactory.ID); assertThat(commandFailedEventCaptor.getValue().getErrorMessage()).isNotEmpty(); } } @@ -196,7 +179,6 @@ class ArchiveEventListenerTest { private final Command command = CommandTestFactory.create(); private final VorgangLockedEvent event = new VorgangLockedEvent(command); - private final XtaFile xdomeaFile = XdomeaXtaFileTestFactory.create(); @BeforeEach void mock() { @@ -223,30 +205,18 @@ class ArchiveEventListenerTest { @BeforeEach void mock() { doNothing().when(eventListener).runWithSecurityContext(any(), any()); - doNothing().when(eventListener).sendXdomeaFile(any()); } @Test - void shouldCallBuildXdomeaXtaFile() { + void shouldCallRunWithSecurityContext() { onVorgangLockedEvent(); verify(eventListener).runWithSecurityContext(eq(command), commandExecutorCapture.capture()); commandExecutorCapture.getValue().accept(command); - verify(eventListener).buildXdomeaXtaFile(CommandTestFactory.VORGANG_ID); - } - - @Test - void shouldCallSendXdomeaFile() { - doReturn(xdomeaFile).when(eventListener).buildXdomeaXtaFile(CommandTestFactory.VORGANG_ID); - onVorgangLockedEvent(); + verify(exportService).archiveVorgang(command); - verify(eventListener).runWithSecurityContext(eq(command), commandExecutorCapture.capture()); - commandExecutorCapture.getValue().accept(command); - - verify(eventListener).sendXdomeaFile(xdomeaFile); } - } private void onVorgangLockedEvent() { @@ -259,30 +229,32 @@ class ArchiveEventListenerTest { @Test void shouldCallCommandServiceForPendingCommandsOnce() { - when(commandService.hasPendingCommands(any())).thenReturn(false); + when(commandService.hasPendingCommandsExceptWithOrder(any(), any())).thenReturn(false); waitForPendingCommandsToFinish(); - verify(commandService).hasPendingCommands(VorgangWithEingangTestFactory.ID); + verify(commandService).hasPendingCommandsExceptWithOrder(VorgangWithEingangTestFactory.ID, ArchiveEventListener.ARCHIVE_VORGANG_ORDER); } @Test void shouldCallCommandServiceForPendingCommandsTwice() { - when(commandService.hasPendingCommands(any())).thenReturn(true) + when(commandService.hasPendingCommandsExceptWithOrder(any(), any())).thenReturn(true) .thenReturn(false); waitForPendingCommandsToFinish(); - verify(commandService, times(2)).hasPendingCommands(VorgangWithEingangTestFactory.ID); + verify(commandService, times(2)).hasPendingCommandsExceptWithOrder(VorgangWithEingangTestFactory.ID, + ArchiveEventListener.ARCHIVE_VORGANG_ORDER); } @Test - void shouldCallAbortWaitingAfterThreeAttempts() { - when(commandService.hasPendingCommands(any())).thenReturn(true); + void shouldCallAbortWaitingAfterMaxAttempts() { + when(commandService.hasPendingCommandsExceptWithOrder(any(), any())).thenReturn(true); var timeoutExceptionThrown = waitForPendingCommandsToFinishAndCatchException(); - verify(commandService, times(3)).hasPendingCommands(VorgangWithEingangTestFactory.ID); + verify(commandService, times(ArchiveEventListener.MAXIMUM_CHECKS_FOR_PENDING_COMMANDS)) + .hasPendingCommandsExceptWithOrder(VorgangWithEingangTestFactory.ID, ArchiveEventListener.ARCHIVE_VORGANG_ORDER); assertThat(timeoutExceptionThrown).isTrue(); } @@ -300,287 +272,4 @@ class ArchiveEventListenerTest { } } - @Nested - class TestBuildXdomeaXtaFile { - - private final String fileNameId = UUID.randomUUID().toString(); - - @BeforeEach - void mock() { - doReturn(fileNameId).when(eventListener).createFileNameId(); - when(exportService.buildXdomeaFileName(fileNameId)).thenReturn(XdomeaXtaFileTestFactory.FILE_NAME); - } - - @Test - void shouldCallCreateFileNameId() { - buildXdomeaXtaFile(); - - verify(eventListener).createFileNameId(); - } - - @Test - void shouldCallBuildXdomeaFileName() { - buildXdomeaXtaFile(); - - verify(exportService).buildXdomeaFileName(fileNameId); - } - - @Test - void shouldCallCreateFileContent() { - buildXdomeaXtaFile(); - - verify(eventListener).createFileContent(VorgangWithEingangTestFactory.ID, fileNameId); - } - - @Test - void shouldReturnXdomeaFile() { - doReturn(XdomeaXtaFileTestFactory.DATA_HANDLER).when(eventListener).createFileContent(VorgangWithEingangTestFactory.ID, fileNameId); - - var xdomeaFile = buildXdomeaXtaFile(); - - assertThat(xdomeaFile).usingRecursiveComparison().isEqualTo(XdomeaXtaFileTestFactory.create()); - } - - private XtaFile buildXdomeaXtaFile() { - return eventListener.buildXdomeaXtaFile(VorgangWithEingangTestFactory.ID); - } - } - - @Nested - class TestCreateFileNameId { - - private final UUID uuid = UUID.randomUUID(); - - @Test - void shouldReturnRandomUUID() { - try (var mockedStaticUUID = mockStatic(UUID.class)) { - mockedStaticUUID.when(UUID::randomUUID).thenReturn(uuid); - - var returnedFileNameId = eventListener.createFileNameId(); - - assertThat(returnedFileNameId).isEqualTo(uuid.toString()); - } - } - } - - @Nested - class TestCreateFileContent { - - private final String fileNameId = UUID.randomUUID().toString(); - - @Nested - class OnNoExceptionThrown { - private MockedConstruction<FileDataSource> fileDataSourceConstruction; - private FileDataSource fileDataSource; - private File dataSourceFile; - - private MockedConstruction<DataHandler> dataHandlerConstruction; - private DataHandler dataHandler; - private FileDataSource dataHandlerSource; - - @Mock - private File tempFile; - @Mock - private OutputStream outputStream; - - @BeforeEach - @SneakyThrows - void setUpMock() { - doReturn(tempFile).when(eventListener).createTempFile(fileNameId); - fileDataSourceConstruction = mockConstruction(FileDataSource.class, - (fileDataSource, context) -> { - dataSourceFile = (File) context.arguments().get(0); - this.fileDataSource = fileDataSource; - when(fileDataSource.getOutputStream()).thenReturn(outputStream); - }); - dataHandlerConstruction = mockConstruction(DataHandler.class, (dataHandler, context) -> { - this.dataHandler = dataHandler; - dataHandlerSource = (FileDataSource) context.arguments().get(0); - }); - } - - @AfterEach - void cleanUp() { - fileDataSourceConstruction.close(); - dataHandlerConstruction.close(); - } - - @Test - @SneakyThrows - void shouldCallCreateTempFile() { - createFileContent(); - - verify(eventListener).createTempFile(fileNameId); - } - - @Test - void shouldCreateFileDataSourceWithTempFile() { - createFileContent(); - - assertThat(dataSourceFile).isEqualTo(tempFile); - } - - @Test - @SneakyThrows - void shouldGetOutputStreamOfFileDataSource() { - createFileContent(); - - verify(fileDataSource).getOutputStream(); - } - - @Test - void shouldWriteXdomeaContentToOutputStream() { - createFileContent(); - - verify(exportService).writeXdomeaFileContent(VorgangWithEingangTestFactory.ID, fileNameId, outputStream); - } - - @Test - void shouldConstructDataHandlerFromFileDataSource() { - createFileContent(); - - assertThat(dataHandlerConstruction.constructed()).hasSize(1); - assertThat(dataHandlerSource).isEqualTo(fileDataSource); - } - - @Test - void shouldReturnDataHandler() { - var resultDataHandler = createFileContent(); - - assertThat(resultDataHandler).isEqualTo(dataHandler); - } - } - - @Nested - class OnIOExceptionThrown { - @Test - @SneakyThrows - void shouldThrowTechnicalExcpetion() { - doThrow(IOException.class).when(eventListener).createTempFile(any()); - - assertThrows(TechnicalException.class, () -> createFileContent()); - } - } - - private DataHandler createFileContent() { - return eventListener.createFileContent(VorgangWithEingangTestFactory.ID, fileNameId); - } - } - - @Nested - class TestCreateTempFile { - - private final String fileNameId = UUID.randomUUID().toString(); - - @Test - @SneakyThrows - void shouldReturnFile() { - var file = eventListener.createTempFile(fileNameId); - - assertThat(file).isNotNull().isInstanceOf(File.class); - } - } - - @Nested - class TestSendXdomeaFile { - - private final XtaFile xdomeaFile = XdomeaXtaFileTestFactory.create(); - - @Mock - private XtaMessage xtaMessage; - - @BeforeEach - void mock() { - doReturn(xtaMessage).when(eventListener).createMessage(xdomeaFile); - } - - @Test - @SneakyThrows - void shouldCallCreateMessage() { - sendXdomeaFile(); - - verify(eventListener).createMessage(xdomeaFile); - } - - @Test - @SneakyThrows - void shouldSendMessage() { - sendXdomeaFile(); - - verify(xtaClient).sendMessage(xtaMessage); - } - - @Test - @SneakyThrows - void shouldThrowTechnicalException() { - when(xtaClient.sendMessage(any())).thenThrow(XtaClientException.class); - - assertThrows(TechnicalException.class, () -> sendXdomeaFile()); - } - - private void sendXdomeaFile() { - eventListener.sendXdomeaFile(xdomeaFile); - } - } - - @Nested - class TestCreateMessage { - private final XtaFile xdomeaFile = XdomeaXtaFileTestFactory.create(); - - private MockedStatic<XdomeaXtaMessageCreator> mockedStaticXdomeaXtaMessageCreator; - - @Mock - private XdomeaXtaMessageCreator xdomeaXtaMessageCreator; - @Mock - private XtaMessage xtaMessage; - - @BeforeEach - void setUpMock() { - mockedStaticXdomeaXtaMessageCreator = mockStatic(XdomeaXtaMessageCreator.class); - mockedStaticXdomeaXtaMessageCreator.when(XdomeaXtaMessageCreator::createInstance).thenReturn(xdomeaXtaMessageCreator); - } - - @AfterEach - void cleanUp() { - mockedStaticXdomeaXtaMessageCreator.close(); - } - - @Test - void shouldCreateXdomeaXtaMessageCreator() { - createMessage(); - - mockedStaticXdomeaXtaMessageCreator.verify(XdomeaXtaMessageCreator::createInstance); - } - - @Test - @SneakyThrows - void shouldCallCreateMessage() { - createMessage(); - - verify(xdomeaXtaMessageCreator).createMessage(xdomeaFile); - } - - @Test - @SneakyThrows - void shouldReturnMessage() { - when(xdomeaXtaMessageCreator.createMessage(any())).thenReturn(xtaMessage); - - var message = createMessage(); - - assertThat(message).isEqualTo(xtaMessage); - } - - @Test - @SneakyThrows - void shouldThrowTechnicalException() { - when(xdomeaXtaMessageCreator.createMessage(any())).thenThrow(XtaClientException.class); - - assertThrows(TechnicalException.class, () -> createMessage()); - } - - private XtaMessage createMessage() { - return eventListener.createMessage(xdomeaFile); - } - - } } \ No newline at end of file diff --git a/archive-manager-server/src/test/java/de/ozgcloud/archive/vorgang/ExportVorgangServiceTest.java b/archive-manager-server/src/test/java/de/ozgcloud/archive/vorgang/ExportVorgangServiceTest.java deleted file mode 100644 index f5e4f059002b028ce6d91d9ef823132ab6fe0c7e..0000000000000000000000000000000000000000 --- a/archive-manager-server/src/test/java/de/ozgcloud/archive/vorgang/ExportVorgangServiceTest.java +++ /dev/null @@ -1,121 +0,0 @@ -package de.ozgcloud.archive.vorgang; - -import static org.assertj.core.api.Assertions.*; -import static org.mockito.Mockito.*; - -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Nested; -import org.junit.jupiter.api.Test; -import org.mockito.InjectMocks; -import org.mockito.Mock; -import org.mockito.Spy; - -import de.ozgcloud.archive.export.AllgemeineMetadatenTypeTestFactory; -import de.ozgcloud.archive.export.IdentifikationObjektTypeTestFactory; - -public class ExportVorgangServiceTest { - - private final static String VORGANG_ID = VorgangWithEingangTestFactory.ID; - private final VorgangWithEingang vorgang = VorgangWithEingangTestFactory.create(); - - @Spy - @InjectMocks - private ExportVorgangService exportVorgangService; - - @Mock - private VorgangRemoteService vorgangRemoteService; - - @Nested - class TestGetVorgang { - - @BeforeEach - void init() { - when(vorgangRemoteService.findVorgangWithEingang(VORGANG_ID)).thenReturn(vorgang); - } - - @Test - void shouldCallVorgangRemoteService() { - callService(); - - verify(vorgangRemoteService).findVorgangWithEingang(VORGANG_ID); - } - - @Test - void shouldReturnVorgangWithEingang() { - var vorgangWithEingang = callService(); - - assertThat(vorgangWithEingang).isEqualTo(vorgang); - } - - private VorgangWithEingang callService() { - return exportVorgangService.getVorgang(VORGANG_ID); - } - } - - @Nested - class TestCreateAkteType { - - @Test - void shouldCallCreateIdentifikationObjektType() { - exportVorgangService.createAkteType(vorgang); - - verify(exportVorgangService).createIdentifikationObjektType(); - } - - @Test - void shouldSetIdentifikationObjektType() { - var identifikationObjektType = IdentifikationObjektTypeTestFactory.create(); - doReturn(identifikationObjektType).when(exportVorgangService).createIdentifikationObjektType(); - - var akteType = exportVorgangService.createAkteType(vorgang); - - assertThat(akteType.getIdentifikation()).isEqualTo(identifikationObjektType); - } - - @Test - void shouldCallCreateAllgemeineMetadatenType() { - exportVorgangService.createAkteType(vorgang); - - verify(exportVorgangService).createAllgemeineMetadatenType(vorgang); - } - - @Test - void shouldSetAllgemeineMetadatenType() { - var allgemeineMetadatenType = AllgemeineMetadatenTypeTestFactory.create(); - doReturn(allgemeineMetadatenType).when(exportVorgangService).createAllgemeineMetadatenType(vorgang); - - var akteType = exportVorgangService.createAkteType(vorgang); - - assertThat(akteType.getAllgemeineMetadaten()).isEqualTo(allgemeineMetadatenType); - } - } - - @Nested - class TestCreateIdentifikationObjektType { - - @Test - void shouldSetID() { - var identifikationObjektType = exportVorgangService.createIdentifikationObjektType(); - - assertThat(identifikationObjektType.getID()).isNotBlank(); - } - } - - @Nested - class TestCreateAllgemeineMetadatenType { - - @Test - void shouldSetKennzeichen() { - var allgemeineMetadatenType = exportVorgangService.createAllgemeineMetadatenType(vorgang); - - assertThat(allgemeineMetadatenType.getKennzeichen()).isEqualTo(VorgangWithEingangTestFactory.AKTENZEICHEN); - } - - @Test - void shouldSetEmptyKennzeichen() { - var akteType = exportVorgangService.createAkteType(VorgangWithEingangTestFactory.createBuilder().aktenzeichen(null).build()); - - assertThat(akteType.getAllgemeineMetadaten().getKennzeichen()).isEmpty(); - } - } -} diff --git a/archive-manager-server/src/test/java/de/ozgcloud/archive/vorgang/KopfCreatorTest.java b/archive-manager-server/src/test/java/de/ozgcloud/archive/vorgang/KopfCreatorTest.java index 1bfd73805170223678faa0ba163ee83baa4ebec1..f85bdeaeb3753d73df4c193540f70f4d104a64e0 100644 --- a/archive-manager-server/src/test/java/de/ozgcloud/archive/vorgang/KopfCreatorTest.java +++ b/archive-manager-server/src/test/java/de/ozgcloud/archive/vorgang/KopfCreatorTest.java @@ -193,7 +193,7 @@ class KopfCreatorTest { class TestCreateKontaktType { @Nested - class OnBehoerdenschluesselNotSet { + class TestOnBehoerdenschluesselNotSet { @ParameterizedTest @NullAndEmptySource @@ -217,7 +217,7 @@ class KopfCreatorTest { } @Nested - class OnBehoerdenschluesselSet { + class TestOnBehoerdenschluesselSet { private static final BehoerdenkennungType expectedValue = new BehoerdenkennungType(); diff --git a/archive-manager-server/src/test/java/de/ozgcloud/archive/vorgang/ExportVorgangServiceITCase.java b/archive-manager-server/src/test/java/de/ozgcloud/archive/vorgang/VorgangServiceITCase.java similarity index 92% rename from archive-manager-server/src/test/java/de/ozgcloud/archive/vorgang/ExportVorgangServiceITCase.java rename to archive-manager-server/src/test/java/de/ozgcloud/archive/vorgang/VorgangServiceITCase.java index 67dd7e23b03f61bc7cc68eff597e4110c85d4dfb..9bca539cd8db32349881da4186e00aa73cbe0799 100644 --- a/archive-manager-server/src/test/java/de/ozgcloud/archive/vorgang/ExportVorgangServiceITCase.java +++ b/archive-manager-server/src/test/java/de/ozgcloud/archive/vorgang/VorgangServiceITCase.java @@ -17,10 +17,10 @@ import de.xoev.xdomea.AntragsdatenItemType; import de.xoev.xdomea.AntragsdatenSingleValueFieldType; @ITCase -class ExportVorgangServiceITCase { +class VorgangServiceITCase { @Autowired - private ExportVorgangService exportVorgangService; + private VorgangService vorgangService; @Nested class TestMapVorgang { @@ -38,7 +38,7 @@ class ExportVorgangServiceITCase { @Test void shouldContainSingleAntragsdatenElement() { - var vorgangType = exportVorgangService.createVorgangType(VorgangWithEingangTestFactory.create()); + var vorgangType = vorgangService.createVorgangType(VorgangWithEingangTestFactory.create()); assertThat(vorgangType.getAnwendungsspezifischeErweiterungXML().getAny()).hasSize(1).first().isInstanceOf(Antragsdaten.class); } @@ -91,7 +91,7 @@ class ExportVorgangServiceITCase { .antragsteller(AntragstellerTestFactory.createBuilder().otherData(OTHER_DATA).build()) .build(); var vorgangWithEingang = VorgangWithEingangTestFactory.createBuilder().eingang(eingang).build(); - var vorgangType = exportVorgangService.createVorgangType(vorgangWithEingang); + var vorgangType = vorgangService.createVorgangType(vorgangWithEingang); return (Antragsdaten) vorgangType.getAnwendungsspezifischeErweiterungXML().getAny().get(0); } } diff --git a/archive-manager-server/src/test/java/de/ozgcloud/archive/vorgang/VorgangServiceTest.java b/archive-manager-server/src/test/java/de/ozgcloud/archive/vorgang/VorgangServiceTest.java new file mode 100644 index 0000000000000000000000000000000000000000..98f5ffd07a64fba795c90595cddcb5e13defebc0 --- /dev/null +++ b/archive-manager-server/src/test/java/de/ozgcloud/archive/vorgang/VorgangServiceTest.java @@ -0,0 +1,358 @@ +package de.ozgcloud.archive.vorgang; + +import static org.assertj.core.api.Assertions.*; +import static org.mockito.ArgumentMatchers.*; +import static org.mockito.Mockito.*; + +import java.util.Map; +import java.util.Optional; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.Spy; + +import de.ozgcloud.apilib.common.command.OzgCloudCommand; +import de.ozgcloud.apilib.common.command.OzgCloudCommandService; +import de.ozgcloud.apilib.common.command.OzgCloudCreateSubCommandsRequest; +import de.ozgcloud.apilib.common.command.OzgCloudCreateSubCommandsRequestTestFactory; +import de.ozgcloud.apilib.common.command.grpc.CommandMapper; +import de.ozgcloud.apilib.common.command.grpc.OzgCloudCommandTestFactory; +import de.ozgcloud.apilib.common.datatypes.GenericId; +import de.ozgcloud.apilib.user.OzgCloudUserId; +import de.ozgcloud.apilib.vorgang.OzgCloudVorgangId; +import de.ozgcloud.apilib.vorgang.OzgCloudVorgangIdMapper; +import de.ozgcloud.archive.common.callcontext.CallContextUser; +import de.ozgcloud.archive.common.callcontext.CallContextUserTestFactory; +import de.ozgcloud.archive.common.callcontext.CurrentUserService; +import de.ozgcloud.archive.export.AllgemeineMetadatenTypeTestFactory; +import de.ozgcloud.archive.export.IdentifikationObjektTypeTestFactory; +import de.ozgcloud.command.Command; +import de.ozgcloud.command.CommandTestFactory; + +public class VorgangServiceTest { + + private static final String VORGANG_ID = VorgangWithEingangTestFactory.ID; + private final VorgangWithEingang vorgang = VorgangWithEingangTestFactory.create(); + + @Spy + @InjectMocks + private VorgangService vorgangService; + + @Mock + private VorgangRemoteService vorgangRemoteService; + @Mock + private OzgCloudCommandService ozgCloudCommandService; + @Mock + private CurrentUserService currentUserService; + @Mock + private OzgCloudVorgangIdMapper ozgCloudVorgangIdMapper; + @Mock + private CommandMapper commandMapper; + + @Nested + class TestGetVorgang { + + @BeforeEach + void init() { + when(vorgangRemoteService.findVorgangWithEingang(VORGANG_ID)).thenReturn(vorgang); + } + + @Test + void shouldCallVorgangRemoteService() { + callService(); + + verify(vorgangRemoteService).findVorgangWithEingang(VORGANG_ID); + } + + @Test + void shouldReturnVorgangWithEingang() { + var vorgangWithEingang = callService(); + + assertThat(vorgangWithEingang).isEqualTo(vorgang); + } + + private VorgangWithEingang callService() { + return vorgangService.getVorgang(VORGANG_ID); + } + } + + @Nested + class TestCreateAkteType { + + @Test + void shouldCallCreateIdentifikationObjektType() { + vorgangService.createAkteType(vorgang); + + verify(vorgangService).createIdentifikationObjektType(); + } + + @Test + void shouldSetIdentifikationObjektType() { + var identifikationObjektType = IdentifikationObjektTypeTestFactory.create(); + doReturn(identifikationObjektType).when(vorgangService).createIdentifikationObjektType(); + + var akteType = vorgangService.createAkteType(vorgang); + + assertThat(akteType.getIdentifikation()).isEqualTo(identifikationObjektType); + } + + @Test + void shouldCallCreateAllgemeineMetadatenType() { + vorgangService.createAkteType(vorgang); + + verify(vorgangService).createAllgemeineMetadatenType(vorgang); + } + + @Test + void shouldSetAllgemeineMetadatenType() { + var allgemeineMetadatenType = AllgemeineMetadatenTypeTestFactory.create(); + doReturn(allgemeineMetadatenType).when(vorgangService).createAllgemeineMetadatenType(vorgang); + + var akteType = vorgangService.createAkteType(vorgang); + + assertThat(akteType.getAllgemeineMetadaten()).isEqualTo(allgemeineMetadatenType); + } + } + + @Nested + class TestCreateIdentifikationObjektType { + + @Test + void shouldSetID() { + var identifikationObjektType = vorgangService.createIdentifikationObjektType(); + + assertThat(identifikationObjektType.getID()).isNotBlank(); + } + } + + @Nested + class TestCreateAllgemeineMetadatenType { + + @Test + void shouldSetKennzeichen() { + var allgemeineMetadatenType = vorgangService.createAllgemeineMetadatenType(vorgang); + + assertThat(allgemeineMetadatenType.getKennzeichen()).isEqualTo(VorgangWithEingangTestFactory.AKTENZEICHEN); + } + + @Test + void shouldSetEmptyKennzeichen() { + var akteType = vorgangService.createAkteType(VorgangWithEingangTestFactory.createBuilder().aktenzeichen(null).build()); + + assertThat(akteType.getAllgemeineMetadaten().getKennzeichen()).isEmpty(); + } + } + + @Nested + class TestLockVorgang { + + private static final Command COMMAND = CommandTestFactory.create(); + private static final OzgCloudCommand SUB_COMMAND = OzgCloudCommandTestFactory.create(); + private static final OzgCloudCreateSubCommandsRequest CREATE_SUB_COMMANDS_REQUEST = OzgCloudCreateSubCommandsRequestTestFactory.create(); + + @BeforeEach + void init() { + doReturn(SUB_COMMAND).when(vorgangService).buildLockVorgangSubCommand(any()); + doReturn(CREATE_SUB_COMMANDS_REQUEST).when(vorgangService).buildCreateSubCommandsRequest(any(), any()); + } + + @Test + void shouldCallBuildLockVorgangSubCommand() { + vorgangService.lockVorgang(COMMAND); + + verify(vorgangService).buildLockVorgangSubCommand(COMMAND); + } + + @Test + void shouldCallBuildCreateSubCommandsRequest() { + vorgangService.lockVorgang(COMMAND); + + verify(vorgangService).buildCreateSubCommandsRequest(CommandTestFactory.ID, SUB_COMMAND); + } + + @Test + void shouldCallAddSubCommands() { + vorgangService.lockVorgang(COMMAND); + + verify(ozgCloudCommandService).addSubCommands(CREATE_SUB_COMMANDS_REQUEST); + } + } + + @Nested + class TestBuildLockVorgangSubCommand { + + private static final long RELATION_VERSION = 10; + private static final Command COMMAND = CommandTestFactory.createBuilder().relationVersion(RELATION_VERSION).build(); + + @BeforeEach + void init() { + doReturn(Optional.of(OzgCloudCommandTestFactory.CREATED_BY)).when(vorgangService).getUserId(); + } + + @Test + void shouldSetOrder() { + var result = vorgangService.buildLockVorgangSubCommand(COMMAND); + + assertThat(result.getOrder()).isEqualTo(VorgangService.LOCK_VORGANG_ORDER); + } + + @Test + void shouldSetVorgangId() { + when(commandMapper.toOzgCloudVorgangId(anyString())).thenReturn(OzgCloudVorgangId.from(CommandTestFactory.VORGANG_ID)); + + var result = vorgangService.buildLockVorgangSubCommand(COMMAND); + + verify(commandMapper).toOzgCloudVorgangId(CommandTestFactory.VORGANG_ID); + assertThat(result.getVorgangId()).hasToString(CommandTestFactory.VORGANG_ID); + } + + @Test + void shouldSetRelationId() { + when(commandMapper.mapRelationId(anyString())).thenReturn(GenericId.from(CommandTestFactory.VORGANG_ID)); + + var result = vorgangService.buildLockVorgangSubCommand(COMMAND); + + verify(commandMapper).mapRelationId(CommandTestFactory.VORGANG_ID); + assertThat(result.getRelationId()).hasToString(CommandTestFactory.VORGANG_ID); + } + + @Test + void shouldSetRelationVersion() { + var result = vorgangService.buildLockVorgangSubCommand(COMMAND); + + assertThat(result.getRelationVersion()).isEqualTo(RELATION_VERSION); + } + + @Test + void shouldCallBuildObjectBody() { + vorgangService.buildLockVorgangSubCommand(COMMAND); + + verify(vorgangService).buildObjectBody(); + } + + @Test + void shouldSetBodyObject() { + var bodyObject = Map.<String, Object>of("key", "value"); + doReturn(bodyObject).when(vorgangService).buildObjectBody(); + + var result = vorgangService.buildLockVorgangSubCommand(COMMAND); + + assertThat(result.getBodyObject()).containsExactlyEntriesOf(bodyObject); + } + + @Test + void shouldCallGetUserId() { + vorgangService.buildLockVorgangSubCommand(COMMAND); + + verify(vorgangService).getUserId(); + } + + @Test + void shouldSetCreatedBy() { + var result = vorgangService.buildLockVorgangSubCommand(COMMAND); + + assertThat(result.getCreatedBy()).isEqualTo(OzgCloudCommandTestFactory.CREATED_BY); + } + } + + @Nested + class TestBuildObjectBody { + + @Test + void shouldReturnBodyObject() { + var result = vorgangService.buildObjectBody(); + + assertThat(result).containsExactly(Map.entry(VorgangService.KEY_LOCK_VORGANG_REASON, VorgangService.LOCK_VORGANG_REASON)); + } + } + + @Nested + class TestGetUserId { + + @Nested + class TestWithUser { + + private static final CallContextUser CALL_CONTEXT_USER = CallContextUserTestFactory.create(); + + @BeforeEach + void init() { + when(currentUserService.findUser()).thenReturn(Optional.of(CALL_CONTEXT_USER)); + } + + @Test + void shouldCallFindUserId() { + vorgangService.getUserId(); + + verify(currentUserService).findUser(); + } + + @Test + void shouldReturnUserId() { + when(commandMapper.toOzgCloudUserId(anyString())).thenReturn(OzgCloudUserId.from(CallContextUserTestFactory.USER_ID)); + + var result = vorgangService.getUserId(); + + verify(commandMapper).toOzgCloudUserId(CallContextUserTestFactory.USER_ID); + assertThat(result).get().hasToString(CallContextUserTestFactory.USER_ID); + } + } + + @Nested + class TestMissingUser { + + @Test + void shouldHandleMissingUser() { + var result = vorgangService.getUserId(); + + assertThat(result).isEmpty(); + } + + @Test + void shouldHandleMissingUserId() { + when(currentUserService.findUser()).thenReturn( + Optional.of(CallContextUserTestFactory.createBuilder().userId(Optional.empty()).build())); + + var result = vorgangService.getUserId(); + + assertThat(result).isEmpty(); + } + } + } + + @Nested + class TestBuildCreateSubCommandsRequest { + + @Test + void shouldSetParentId() { + var result = vorgangService.buildCreateSubCommandsRequest(CommandTestFactory.ID, OzgCloudCommandTestFactory.create()); + + assertThat(result.getParentId()).isEqualTo(CommandTestFactory.ID); + } + + @Test + void shouldSetSubCommand() { + var subCommand = OzgCloudCommandTestFactory.create(); + + var result = vorgangService.buildCreateSubCommandsRequest(CommandTestFactory.ID, subCommand); + + assertThat(result.getSubCommands()).containsExactly(subCommand); + } + + @Test + void shouldSetCompletedIfSubsCompleted() { + var result = vorgangService.buildCreateSubCommandsRequest(CommandTestFactory.ID, OzgCloudCommandTestFactory.create()); + + assertThat(result.isCompletedIfSubsCompleted()).isFalse(); + } + + @Test + void shouldSetExecutionMode() { + var result = vorgangService.buildCreateSubCommandsRequest(CommandTestFactory.ID, OzgCloudCommandTestFactory.create()); + + assertThat(result.getExecutionMode()).isEqualTo(VorgangService.SUB_COMMAND_EXECUTION_MODE); + } + } +} diff --git a/archive-manager-server/src/test/java/de/ozgcloud/archive/xta/XtaServiceTest.java b/archive-manager-server/src/test/java/de/ozgcloud/archive/xta/XtaServiceTest.java index ab324d996b94fb8220a680de855bbeb57a6dc323..eca8e2904fa8840c4f730e55c21e0c72883026e0 100644 --- a/archive-manager-server/src/test/java/de/ozgcloud/archive/xta/XtaServiceTest.java +++ b/archive-manager-server/src/test/java/de/ozgcloud/archive/xta/XtaServiceTest.java @@ -24,7 +24,6 @@ import de.ozgcloud.archive.common.command.CommandService; import de.ozgcloud.archive.common.command.CommandTestFactory; import de.ozgcloud.archive.vorgang.VorgangWithEingangTestFactory; import de.ozgcloud.archive.xta.XtaImportConfirmationHandler.XtaAbgabeHandler; -import de.ozgcloud.command.Command; import de.ozgcloud.command.CommandExecutedEvent; import de.ozgcloud.command.CommandFailedEvent; import de.ozgcloud.common.errorhandling.TechnicalException; @@ -158,8 +157,8 @@ class XtaServiceTest { @Nested class TestOnExistingPendingCommands { - private final Command command = CommandTestFactory.create(); - private final List<Command> commands = List.of(command); + private final ArchiveManagerCommand command = CommandTestFactory.create(); + private final List<ArchiveManagerCommand> commands = List.of(command); @BeforeEach void mock() { @@ -194,8 +193,8 @@ class XtaServiceTest { @Mock private XtaAbgabeHandler abgabeHandler; - private final Command command = CommandTestFactory.create(); - private final List<Command> commands = List.of(command, command); + private final ArchiveManagerCommand command = CommandTestFactory.create(); + private final List<ArchiveManagerCommand> commands = List.of(command, command); @Test void shouldCallIsSuccessfullyDone() { diff --git a/archive-manager-server/src/test/resources/application-itcase.yaml b/archive-manager-server/src/test/resources/application-itcase.yaml index f2a8a5d0796d5ec6483ce121ae70e06afe5b7686..9bd1a3bb14e6dac750aca9251cb49cad90684702 100644 --- a/archive-manager-server/src/test/resources/application-itcase.yaml +++ b/archive-manager-server/src/test/resources/application-itcase.yaml @@ -11,10 +11,7 @@ ozgcloud: keystore: file: classpath:xtaTestStore.p12 password: changeit - clientIdentifiers: - - name: - category: Generischer Antragsempfänger - value: gae:dev-environment@ozg-cloud.de + clientIdentifiers: '[{"category":"Generischer Antragsempfänger","name":"ozg-cloud dev","value":"gae:dev-environment@ozg-cloud.de"}]' grpc: server: diff --git a/lombok.config b/lombok.config index a0e918012b6da2b2cd06374cf7ac35d085bfa3e0..8e315e3261a9b09aaf535702db799d3991736230 100644 --- a/lombok.config +++ b/lombok.config @@ -28,4 +28,5 @@ lombok.log.log4j.flagUsage = ERROR lombok.data.flagUsage = ERROR lombok.nonNull.exceptionType = IllegalArgumentException lombok.addLombokGeneratedAnnotation = true -lombok.copyableAnnotations += org.springframework.beans.factory.annotation.Qualifier \ No newline at end of file +lombok.copyableAnnotations += org.springframework.beans.factory.annotation.Qualifier +lombok.copyableAnnotations += net.devh.boot.grpc.client.inject.GrpcClient diff --git a/pom.xml b/pom.xml index 92543877d7685411887e7fd18ef06f64204237e4..5c31ba4d403d7254f6296eb87f85967f385b6157 100644 --- a/pom.xml +++ b/pom.xml @@ -7,12 +7,12 @@ <parent> <groupId>de.ozgcloud.common</groupId> <artifactId>ozgcloud-common-parent</artifactId> - <version>4.6.0-SNAPSHOT</version> + <version>4.7.0</version> </parent> <groupId>de.ozgcloud.archive</groupId> <artifactId>archive-manager</artifactId> - <version>0.1.0-SNAPSHOT</version> + <version>0.2.0-SNAPSHOT</version> <packaging>pom</packaging> <modules> @@ -25,13 +25,13 @@ <maven.compiler.target>${java.version}</maven.compiler.target> <jaxb2-maven-plugin.version>3.1.0</jaxb2-maven-plugin.version> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> - <vorgang-manager.version>2.18.0-SNAPSHOT</vorgang-manager.version> - <nachrichten-manager.version>2.15.0-SNAPSHOT</nachrichten-manager.version> - <api-lib.version>0.13.0</api-lib.version> + <vorgang-manager.version>2.18.0</vorgang-manager.version> + <nachrichten-manager.version>2.15.0</nachrichten-manager.version> + <api-lib.version>0.16.0-PR-38-SNAPSHOT</api-lib.version> <find-and-replace-maven-plugin.version>1.2.0</find-and-replace-maven-plugin.version> <protoc-jar-plugin.version>3.11.4</protoc-jar-plugin.version> - <ozgcloud-common.version>4.6.0-SNAPSHOT</ozgcloud-common.version> - <document-manager.version>1.1.0-SNAPSHOT</document-manager.version> + <ozgcloud-common.version>4.7.0</ozgcloud-common.version> + <document-manager.version>1.1.0</document-manager.version> <xta-client-lib.version>0.1.0</xta-client-lib.version> </properties> <dependencyManagement>