diff --git a/pluto-server/pom.xml b/pluto-server/pom.xml index 42231e157c9cacd03e2808a63a14a8257218be2e..af2771983ef12139ced3b475b0d59fca6ffae961 100644 --- a/pluto-server/pom.xml +++ b/pluto-server/pom.xml @@ -49,6 +49,7 @@ <kop.license.version>1.3.0</kop.license.version> <kop.zufi.version>0.1.0-SNAPSHOT</kop.zufi.version> + <user-manager-interface.version>1.4.0-SNAPSHOT</user-manager-interface.version> <zip.version>2.11.1</zip.version> <jsoup.version>1.15.3</jsoup.version> @@ -88,6 +89,22 @@ <artifactId>kop-zufi-api</artifactId> <version>${kop.zufi.version}</version> </dependency> + + <dependency> + <groupId>de.itvsh.kop.user</groupId> + <artifactId>user-manager-interface</artifactId> + <version>${user-manager-interface.version}</version> + <exclusions> + <exclusion> + <groupId>io.grpc</groupId> + <artifactId>grpc-core</artifactId> + </exclusion> + <exclusion> + <groupId>org.jboss.slf4j</groupId> + <artifactId>slf4j-jboss-logmanager</artifactId> + </exclusion> + </exclusions> + </dependency> <!-- Spring --> <dependency> diff --git a/pluto-server/src/main/java/de/itvsh/ozg/pluto/common/callcontext/RequestIdClientCallContextAttachingInterceptor.java b/pluto-server/src/main/java/de/itvsh/ozg/pluto/common/callcontext/RequestIdClientCallContextAttachingInterceptor.java new file mode 100644 index 0000000000000000000000000000000000000000..18255f6195542f800e7223fa83da8a8686187ccc --- /dev/null +++ b/pluto-server/src/main/java/de/itvsh/ozg/pluto/common/callcontext/RequestIdClientCallContextAttachingInterceptor.java @@ -0,0 +1,79 @@ +/* + * Copyright (C) 2022 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.itvsh.ozg.pluto.common.callcontext; + +import java.util.UUID; + +import io.grpc.CallOptions; +import io.grpc.Channel; +import io.grpc.ClientCall; +import io.grpc.ClientInterceptor; +import io.grpc.ForwardingClientCall.SimpleForwardingClientCall; +import io.grpc.Metadata; +import io.grpc.Metadata.Key; +import io.grpc.MethodDescriptor; + +public class RequestIdClientCallContextAttachingInterceptor implements ClientInterceptor { + + static final String KEY_REQUEST_ID = "REQUEST_ID-bin"; + + // <A> = Request, <B> = Response + @Override + public <A, B> ClientCall<A, B> interceptCall(MethodDescriptor<A, B> method, CallOptions callOptions, Channel next) { + return new CallContextAttachingClientCall<>(next.newCall(method, callOptions)); + } + + final class CallContextAttachingClientCall<A, B> extends SimpleForwardingClientCall<A, B> { + + protected CallContextAttachingClientCall(ClientCall<A, B> delegate) { + super(delegate); + } + + @Override + public void start(Listener<B> responseListener, Metadata headers) { + headers.merge(buildCallContextMetadata()); + super.start(responseListener, headers); + } + + private Metadata buildCallContextMetadata() { + var metadata = new Metadata(); + + metadata.put(createKeyOf(KEY_REQUEST_ID), generateRequestId().getBytes()); + + return metadata; + } + + // TODO OZG-1974 requestId zentraler erzeugen + private String generateRequestId() { + return UUID.randomUUID().toString(); + } + + } + + // TODO move to common grpc utils + public static Key<byte[]> createKeyOf(String key) { + return Key.of(key, Metadata.BINARY_BYTE_MARSHALLER); + } + +} diff --git a/pluto-server/src/main/java/de/itvsh/ozg/pluto/registry/RegistryScheduler.java b/pluto-server/src/main/java/de/itvsh/ozg/pluto/registry/RegistryScheduler.java index 06ca63659b853cfe74216635d385ab634e313aec..08bf492df7c164c655638d62a40afefab85d7905 100644 --- a/pluto-server/src/main/java/de/itvsh/ozg/pluto/registry/RegistryScheduler.java +++ b/pluto-server/src/main/java/de/itvsh/ozg/pluto/registry/RegistryScheduler.java @@ -11,7 +11,7 @@ class RegistryScheduler { @Autowired private RegistryService registryService; - @Scheduled(fixedDelayString = "${kop.vorgangmanager.registry.intervall}", initialDelay = 5, timeUnit = TimeUnit.MINUTES) + @Scheduled(fixedDelayString = "${kop.vorgangmanager.registry.intervall:360}", initialDelay = 1, timeUnit = TimeUnit.MINUTES) void register() { registryService.registerVorgangManager(); } diff --git a/pluto-server/src/main/java/de/itvsh/ozg/pluto/registry/UserOrganisationsEinheitenRemoteService.java b/pluto-server/src/main/java/de/itvsh/ozg/pluto/registry/UserOrganisationsEinheitenRemoteService.java index 9babe2cd3ea28246857fcc287cd4baab4a2f2cc7..1c8751419984e65af6b81f8e4b3226cd4b3e1585 100644 --- a/pluto-server/src/main/java/de/itvsh/ozg/pluto/registry/UserOrganisationsEinheitenRemoteService.java +++ b/pluto-server/src/main/java/de/itvsh/ozg/pluto/registry/UserOrganisationsEinheitenRemoteService.java @@ -4,11 +4,27 @@ import java.util.List; import org.springframework.stereotype.Service; +import com.google.protobuf.Empty; + +import de.itvsh.kop.user.grpc.organisationseinheit.OrganisationsEinheitServiceGrpc.OrganisationsEinheitServiceBlockingStub; +import de.itvsh.kop.user.organisationseinheit.GrpcOrganisationsEinheit; +import de.itvsh.ozg.pluto.common.callcontext.RequestIdClientCallContextAttachingInterceptor; +import net.devh.boot.grpc.client.inject.GrpcClient; + @Service class UserOrganisationsEinheitenRemoteService { + @GrpcClient("user-manager") + private OrganisationsEinheitServiceBlockingStub serviceStub; + List<String> getSupportedOrganisationsEinheiten() { - return null; + return getGrpcOrganisationsEinheiten().stream().map(GrpcOrganisationsEinheit::getOrganisationsEinheitId) + .toList(); + } + + List<GrpcOrganisationsEinheit> getGrpcOrganisationsEinheiten() { + return serviceStub.withInterceptors(new RequestIdClientCallContextAttachingInterceptor()) + .getSupportedOrganisationsEinheiten(Empty.getDefaultInstance()).getOrganisationseinheitenList(); } } diff --git a/pluto-server/src/main/java/de/itvsh/ozg/pluto/registry/ZufiRemoteService.java b/pluto-server/src/main/java/de/itvsh/ozg/pluto/registry/ZufiRemoteService.java index 569f6d36deeada0d4d6eb358b4ee4aa056dc7276..ee4d2927ecc9163e41bf02378d23ba02faa33b64 100644 --- a/pluto-server/src/main/java/de/itvsh/ozg/pluto/registry/ZufiRemoteService.java +++ b/pluto-server/src/main/java/de/itvsh/ozg/pluto/registry/ZufiRemoteService.java @@ -7,7 +7,7 @@ import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; import de.itvsh.kop.zufi.grpc.registration.GrpcRegistrationRequest; -import de.itvsh.kop.zufi.grpc.registration.RegistrationServiceGrpc; +import de.itvsh.kop.zufi.grpc.registration.RegistrationServiceGrpc.RegistrationServiceBlockingStub; import lombok.NonNull; import lombok.extern.log4j.Log4j2; import net.devh.boot.grpc.client.inject.GrpcClient; @@ -15,25 +15,29 @@ import net.devh.boot.grpc.client.inject.GrpcClient; @Log4j2 @Service class ZufiRemoteService { - @Value(value = "${kop.vorgangmanager.register.external.address:}") + @Value(value = "${kop.vorgangmanager.address:}") private String externalVorgangManagerAddress; @GrpcClient("zufi-manager") - private RegistrationServiceGrpc.RegistrationServiceBlockingStub registryGrpcService; + private RegistrationServiceBlockingStub serviceStub; void registerVorgangManager(@NonNull List<String> organistationsEinheitenIds) { var proceed = checkPreconditions(); if (proceed) { - var request = GrpcRegistrationRequest.newBuilder().addAllOrganisationseinheitenId(organistationsEinheitenIds) - .setAddress(externalVorgangManagerAddress).build(); - registryGrpcService.register(request); + var request = createRequest(organistationsEinheitenIds); + serviceStub.register(request); } } + private GrpcRegistrationRequest createRequest(List<String> organistationsEinheitenIds) { + return GrpcRegistrationRequest.newBuilder().addAllOrganisationseinheitenId(organistationsEinheitenIds) + .setAddress(externalVorgangManagerAddress).build(); + } + boolean checkPreconditions() { if (StringUtils.isEmpty(externalVorgangManagerAddress)) { - LOG.warn("Property kop.vorgangmanager.register.external.address not set. Not registering this VorgangsManager"); + LOG.warn("Property kop.vorgangmanager.address not set. Not registering this VorgangsManager"); return false; } diff --git a/pluto-server/src/main/resources/application-local.yml b/pluto-server/src/main/resources/application-local.yml index d579ea1636eeba4a2b3214b4e253b8f7839fe8a7..d3bda29ff742dba8f6f3c148cb437be1fdfe1f87 100644 --- a/pluto-server/src/main/resources/application-local.yml +++ b/pluto-server/src/main/resources/application-local.yml @@ -33,7 +33,6 @@ spring: username: elastic password: password - pluto: redirect: mail-from: ea@ozg-sh.de @@ -55,6 +54,8 @@ kop: mail-from: ea@ozg-sh.de usermanager: url: http://localhost:9092/migration/user + vorgangmanager: + address: static://127.0.0.1:9090 aktenzeichen: de.itvsh.ozg.pluto.vorgang.AktenzeichenProviderEA diff --git a/pluto-server/src/main/resources/application.yml b/pluto-server/src/main/resources/application.yml index f37dba65d928655467e6ba8a7c18b4e14470b38a..8fcea3451890b3ca03e52ed30a287d2e797652d9 100644 --- a/pluto-server/src/main/resources/application.yml +++ b/pluto-server/src/main/resources/application.yml @@ -31,7 +31,7 @@ grpc: address: self:self negotiationType: PLAINTEXT zufi-manager: - address: static://127.0.0.1:9010 + address: static://127.0.0.1:9190 negotiationType: PLAINTEXT pluto: diff --git a/pluto-server/src/test/java/de/itvsh/ozg/pluto/registry/GrpcGetSupportedOrganisationsEinheitenResponseTestFactory.java b/pluto-server/src/test/java/de/itvsh/ozg/pluto/registry/GrpcGetSupportedOrganisationsEinheitenResponseTestFactory.java new file mode 100644 index 0000000000000000000000000000000000000000..50b598e238bb5c70775643e01d14dc9e5fa8e2c0 --- /dev/null +++ b/pluto-server/src/test/java/de/itvsh/ozg/pluto/registry/GrpcGetSupportedOrganisationsEinheitenResponseTestFactory.java @@ -0,0 +1,17 @@ +package de.itvsh.ozg.pluto.registry; + +import de.itvsh.kop.user.grpc.organisationseinheit.GrpcGetSupportedOrganisationsEinheitenResponse; +import de.itvsh.kop.user.organisationseinheit.GrpcOrganisationsEinheit; + +public class GrpcGetSupportedOrganisationsEinheitenResponseTestFactory { + public static String ORGANISATIONS_EINHEIT_ID = "123456"; + + public static GrpcGetSupportedOrganisationsEinheitenResponse createResponse() { + return createResponseBuilder() + .addOrganisationseinheiten(GrpcOrganisationsEinheit.newBuilder().setOrganisationsEinheitId(ORGANISATIONS_EINHEIT_ID).build()).build(); + } + + public static GrpcGetSupportedOrganisationsEinheitenResponse.Builder createResponseBuilder() { + return GrpcGetSupportedOrganisationsEinheitenResponse.newBuilder(); + } +} diff --git a/pluto-server/src/test/java/de/itvsh/ozg/pluto/registry/GrpcRegistrationResponseTestFactory.java b/pluto-server/src/test/java/de/itvsh/ozg/pluto/registry/GrpcRegistrationResponseTestFactory.java new file mode 100644 index 0000000000000000000000000000000000000000..109a6a3ce36c028fb8e7a13f85efcbb4c6a39637 --- /dev/null +++ b/pluto-server/src/test/java/de/itvsh/ozg/pluto/registry/GrpcRegistrationResponseTestFactory.java @@ -0,0 +1,15 @@ +package de.itvsh.ozg.pluto.registry; + +import de.itvsh.kop.zufi.grpc.registration.GrpcRegistrationResponse; + +class GrpcRegistrationResponseTestFactory { + static final String OK = "OK"; + + static GrpcRegistrationResponse create() { + return createBuilder().build(); + } + + static GrpcRegistrationResponse.Builder createBuilder() { + return GrpcRegistrationResponse.newBuilder().setStatus(OK); + } +} diff --git a/pluto-server/src/test/java/de/itvsh/ozg/pluto/registry/RegistryServiceTest.java b/pluto-server/src/test/java/de/itvsh/ozg/pluto/registry/RegistryServiceTest.java index 54be62dd2e89148fcf82e605d2657345a9dc14c6..c774ab08d5355dcb3a22349fb9b97e781c97804d 100644 --- a/pluto-server/src/test/java/de/itvsh/ozg/pluto/registry/RegistryServiceTest.java +++ b/pluto-server/src/test/java/de/itvsh/ozg/pluto/registry/RegistryServiceTest.java @@ -12,11 +12,16 @@ import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.Spy; +import io.grpc.StatusRuntimeException; + class RegistryServiceTest { @DisplayName("Test registry service") @Nested class TestService { + private static final String ORGANISATIONS_EINHEITEN_ID_1 = "123456"; + private static final String ORGANISATIONS_EINHEITEN_ID_2 = "987654"; + @Spy @InjectMocks private RegistryService registryService; @@ -29,7 +34,8 @@ class RegistryServiceTest { @BeforeEach void init() { - when(userOrganisationsEinheitenRemoteService.getSupportedOrganisationsEinheiten()).thenReturn(List.of("123456", "987654")); + when(userOrganisationsEinheitenRemoteService.getSupportedOrganisationsEinheiten()) + .thenReturn(List.of(ORGANISATIONS_EINHEITEN_ID_1, ORGANISATIONS_EINHEITEN_ID_2)); } @Test @@ -57,12 +63,11 @@ class RegistryServiceTest { @Test void shouldNotCallZuFiRemoteServiceOnException() { - when(userOrganisationsEinheitenRemoteService.getSupportedOrganisationsEinheiten()).thenThrow(Exception.class); + when(userOrganisationsEinheitenRemoteService.getSupportedOrganisationsEinheiten()).thenThrow(StatusRuntimeException.class); registryService.registerVorgangManager(); verify(zufiRemoteService, never()).registerVorgangManager(any()); } } - } diff --git a/pluto-server/src/test/java/de/itvsh/ozg/pluto/registry/UserOrganisationsEinheitenRemoteServiceTest.java b/pluto-server/src/test/java/de/itvsh/ozg/pluto/registry/UserOrganisationsEinheitenRemoteServiceTest.java new file mode 100644 index 0000000000000000000000000000000000000000..da734e4677f693e330fcd4f57b4523d73a482de2 --- /dev/null +++ b/pluto-server/src/test/java/de/itvsh/ozg/pluto/registry/UserOrganisationsEinheitenRemoteServiceTest.java @@ -0,0 +1,50 @@ +package de.itvsh.ozg.pluto.registry; + +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.DisplayName; +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.itvsh.kop.user.grpc.organisationseinheit.OrganisationsEinheitServiceGrpc.OrganisationsEinheitServiceBlockingStub; +import de.itvsh.ozg.pluto.common.callcontext.RequestIdClientCallContextAttachingInterceptor; + +class UserOrganisationsEinheitenRemoteServiceTest { + @DisplayName("Test loading Organsiationseinheiten Ids of the users") + @Nested + class TestLoadingOrganisationsEinheitenIds { + @Spy + @InjectMocks + private UserOrganisationsEinheitenRemoteService remoteService; + + @Mock + private OrganisationsEinheitServiceBlockingStub stub; + + @BeforeEach + void init() { + when(stub.getSupportedOrganisationsEinheiten(any())) + .thenReturn(GrpcGetSupportedOrganisationsEinheitenResponseTestFactory.createResponse()); + } + + @Test + void shouldLoadOrganisationsEinheiten() { + var organisationsEinheiten = remoteService.getSupportedOrganisationsEinheiten(); + + assertThat(organisationsEinheiten).hasSize(1) + .contains(GrpcGetSupportedOrganisationsEinheitenResponseTestFactory.ORGANISATIONS_EINHEIT_ID); + } + + @Test + void shouldUseInterceptor() { + remoteService.getSupportedOrganisationsEinheiten(); + + verify(stub).withInterceptors(any(RequestIdClientCallContextAttachingInterceptor.class)); + } + } +} diff --git a/pluto-server/src/test/java/de/itvsh/ozg/pluto/registry/ZufiManagerRemoteServiceTest.java b/pluto-server/src/test/java/de/itvsh/ozg/pluto/registry/ZufiManagerRemoteServiceTest.java index 7cca9cb85d6ddce805fe2d512500a9cb2f27b58f..933643e1a2ec38bfd4c29f075ec65e091ec30991 100644 --- a/pluto-server/src/test/java/de/itvsh/ozg/pluto/registry/ZufiManagerRemoteServiceTest.java +++ b/pluto-server/src/test/java/de/itvsh/ozg/pluto/registry/ZufiManagerRemoteServiceTest.java @@ -1,37 +1,76 @@ package de.itvsh.ozg.pluto.registry; import static org.assertj.core.api.Assertions.*; +import static org.mockito.ArgumentMatchers.*; +import static org.mockito.Mockito.*; +import java.util.List; + +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.Spy; import org.springframework.test.util.ReflectionTestUtils; +import de.itvsh.kop.zufi.grpc.registration.GrpcRegistrationRequest; +import de.itvsh.kop.zufi.grpc.registration.RegistrationServiceGrpc.RegistrationServiceBlockingStub; + class ZufiManagerRemoteServiceTest { @DisplayName("Test ZuFiRemoteService") @Nested class TestZufiManagerRemoteService { + private static final String ORGANISATIONS_EINHEITEN_ID = "123456"; + private static final List<String> ORGANISATIONS_EINHEITEN_IDS = List.of(ORGANISATIONS_EINHEITEN_ID); @Spy @InjectMocks private ZufiRemoteService zufiRemoteService; + @Mock + private RegistrationServiceBlockingStub serviceStub; + @Test - void shouldProceed() { - ReflectionTestUtils.setField(zufiRemoteService, "externalVorgangManagerAddress", "value"); + void shouldCheckPreconditions() { + zufiRemoteService.registerVorgangManager(ORGANISATIONS_EINHEITEN_IDS); + + verify(zufiRemoteService).checkPreconditions(); + } - var proceed = zufiRemoteService.checkPreconditions(); + @DisplayName("Test ZuFiRemoteService with VorgangManager configured") + @Nested + class TestWithAddress { + @BeforeEach + void init() { + ReflectionTestUtils.setField(zufiRemoteService, "externalVorgangManagerAddress", "value"); + } - assertThat(proceed).isTrue(); + @Test + void shouldProceed() { + var proceed = zufiRemoteService.checkPreconditions(); + + assertThat(proceed).isTrue(); + } + + @Test + void shouldCallServiceStub() { + zufiRemoteService.registerVorgangManager(ORGANISATIONS_EINHEITEN_IDS); + + verify(serviceStub).register(any(GrpcRegistrationRequest.class)); + } } - @Test - void shouldNotProceed() { - var proceed = zufiRemoteService.checkPreconditions(); + @DisplayName("Test ZuFiRemoteService without VorgangManager configured") + @Nested + class TestWithoutAddress { + @Test + void shouldNotProceed() { + var proceed = zufiRemoteService.checkPreconditions(); - assertThat(proceed).isFalse(); + assertThat(proceed).isFalse(); + } } } }