diff --git a/README.md b/README.md index 277d86d22e76df0cfe5f166903f1fc3a69eae299..c5c48801e0aebaf081d7625ef049aa4178931462 100644 --- a/README.md +++ b/README.md @@ -6,6 +6,7 @@ ### 4.6.0 * Update [OZGCloud License Generator](ozgcloud-common-license/readme.md) +* `GrpcUtil` erweitern: mehr Schlüssel hinzufügen und Methoden, um diese Schlüssel aus gRPC-Metadaten zu extrahieren. ### 4.5.0 * common-lib erweitern: gRPC Server Downloader für binäre Dateien hinzufügen diff --git a/ozgcloud-common-lib/src/main/java/de/ozgcloud/common/binaryfile/GrpcBinaryFileServerDownloader.java b/ozgcloud-common-lib/src/main/java/de/ozgcloud/common/binaryfile/GrpcBinaryFileServerDownloader.java index b6bff4a9ca59e8ff7818317a15d176c1660fd695..b992f4236a809f36e95dcf6811d6b80ad0675046 100644 --- a/ozgcloud-common-lib/src/main/java/de/ozgcloud/common/binaryfile/GrpcBinaryFileServerDownloader.java +++ b/ozgcloud-common-lib/src/main/java/de/ozgcloud/common/binaryfile/GrpcBinaryFileServerDownloader.java @@ -25,7 +25,6 @@ package de.ozgcloud.common.binaryfile; import com.google.protobuf.ByteString; import de.ozgcloud.common.errorhandling.TechnicalException; -import io.grpc.Context; import io.grpc.stub.CallStreamObserver; import lombok.Builder; import lombok.extern.log4j.Log4j2; @@ -80,7 +79,7 @@ public class GrpcBinaryFileServerDownloader<T> { void doStart() { LOG.debug("Starting download."); handleSafety(this::setupStreams); - taskExecutor.execute(Context.current().wrap(this::startDownload)); + taskExecutor.execute(this::startDownload); callObserver.setOnReadyHandler(this::sendChunks); } diff --git a/ozgcloud-common-lib/src/main/java/de/ozgcloud/common/grpc/GrpcUtil.java b/ozgcloud-common-lib/src/main/java/de/ozgcloud/common/grpc/GrpcUtil.java index 837309318ef9f4fd230841f2feba7ff30a680569..a5b0e7fc272000f7cd0cd6e80f9681a4ef9e3d61 100644 --- a/ozgcloud-common-lib/src/main/java/de/ozgcloud/common/grpc/GrpcUtil.java +++ b/ozgcloud-common-lib/src/main/java/de/ozgcloud/common/grpc/GrpcUtil.java @@ -24,10 +24,10 @@ package de.ozgcloud.common.grpc; import java.nio.charset.StandardCharsets; -import java.util.ArrayList; import java.util.Collection; import java.util.List; import java.util.Optional; +import java.util.stream.Stream; import java.util.stream.StreamSupport; import io.grpc.Metadata; @@ -39,8 +39,12 @@ import lombok.NoArgsConstructor; public class GrpcUtil { public static final Key<byte[]> HEADER_KEY_USER_ID = createKeyOf("USER_ID-bin"); + public static final Key<byte[]> HEADER_KEY_USER_NAME = createKeyOf("USER_NAME-bin"); public static final Key<byte[]> HEADER_KEY_CLIENT_NAME = createKeyOf("CLIENT_NAME-bin"); - public static final Key<byte[]> HEADER_KEY_REQUEST_ID = createKeyOf("REQUEST_ID-bin"); + public static final String KEY_REQUEST_ID = "REQUEST_ID-bin"; + public static final Key<byte[]> HEADER_KEY_REQUEST_ID = createKeyOf(KEY_REQUEST_ID); + public static final Key<byte[]> HEADER_KEY_ACCESS_LIMITED_ORGAID = createKeyOf("ACCESS_LIMITED_TO_ORGANISATORISCHEEINHEITENID-bin"); + public static final Key<byte[]> HEADER_KEY_ACCESS_LIMITED = createKeyOf("ACCESS_LIMITED-bin"); public static Key<String> keyOfString(String key) { return Key.of(key, Metadata.ASCII_STRING_MARSHALLER); @@ -50,6 +54,30 @@ public class GrpcUtil { return Key.of(key, Metadata.BINARY_BYTE_MARSHALLER); } + public static Optional<String> getRequestId(Metadata headers) { + return getFromHeaders(HEADER_KEY_REQUEST_ID, headers); + } + + public static Optional<String> getClientName(Metadata headers) { + return getFromHeaders(HEADER_KEY_CLIENT_NAME, headers); + } + + public static Optional<String> getUserId(Metadata headers) { + return getFromHeaders(HEADER_KEY_USER_ID, headers); + } + + public static Optional<String> getUserName(Metadata headers) { + return getFromHeaders(HEADER_KEY_USER_NAME, headers); + } + + public static List<String> getAccessLimitedOrgaIds(Metadata headers) { + return getList(HEADER_KEY_ACCESS_LIMITED_ORGAID, headers); + } + + public static Optional<Boolean> getAccessLimited(Metadata headers) { + return getFromHeaders(HEADER_KEY_ACCESS_LIMITED, headers).map(Boolean::parseBoolean); + } + public static Optional<String> getFromHeaders(String key, Metadata headers) { return getFromHeaders(createKeyOf(key), headers); } @@ -58,14 +86,21 @@ public class GrpcUtil { return Optional.ofNullable(headers.get(key)).map(GrpcUtil::byteToString); } - public static Collection<String> getCollection(String key, Metadata headers) { - final List<String> result = new ArrayList<>(); - var valuesOptional = Optional.ofNullable(headers.getAll(createKeyOf(key))); - valuesOptional.ifPresent(valuesBytes -> result.addAll(StreamSupport.stream(valuesBytes.spliterator(), false) - .map(GrpcUtil::byteToString) - .toList())); + /** + * @deprecated since 4.6.0, use {@link #getList(String, Metadata)} instead + */ + @Deprecated(since = "4.6.0", forRemoval = true) + public static List<String> getCollection(String key, Metadata headers) { + return getList(key, headers); + } + + public static List<String> getList(String key, Metadata headers) { + return getList(createKeyOf(key), headers); + } - return result; + public static List<String> getList(Key<byte[]> key, Metadata headers) { + return Optional.ofNullable(headers.getAll(key)).map(valuesBytes -> StreamSupport.stream(valuesBytes.spliterator(), false)) + .orElseGet(Stream::empty).map(GrpcUtil::byteToString).toList(); } private static String byteToString(byte[] bytes) { diff --git a/ozgcloud-common-lib/src/test/java/de/ozgcloud/common/binaryfile/GrpcBinaryFileServerDownloaderTest.java b/ozgcloud-common-lib/src/test/java/de/ozgcloud/common/binaryfile/GrpcBinaryFileServerDownloaderTest.java index 2cda081844610772cc19da6b76a6b52ad71d5b1b..6050e6ba2d06a739e87ec479956dff4fecd707b8 100644 --- a/ozgcloud-common-lib/src/test/java/de/ozgcloud/common/binaryfile/GrpcBinaryFileServerDownloaderTest.java +++ b/ozgcloud-common-lib/src/test/java/de/ozgcloud/common/binaryfile/GrpcBinaryFileServerDownloaderTest.java @@ -121,13 +121,6 @@ class GrpcBinaryFileServerDownloaderTest { @Nested class TestDoStart { - @Mock - private Context callContext; - @Mock - private Runnable wrappedRunnable; - - @Captor - private ArgumentCaptor<Runnable> wrappedRunnableCaptor; @Captor private ArgumentCaptor<Runnable> runnableCaptor; @Captor @@ -145,31 +138,15 @@ class GrpcBinaryFileServerDownloaderTest { verify(downloader).setupStreams(); } - @Test - void shouldCallTaskExecutor() { - try (var contextMock = mockStatic(Context.class)) { - contextMock.when(Context::current).thenReturn(callContext); - when(callContext.wrap(any(Runnable.class))).thenReturn(wrappedRunnable); - - downloader.doStart(); - - verify(taskExecutor).execute(wrappedRunnable); - } - } - @Test void shouldCallStartDownload() { - try (var contextMock = mockStatic(Context.class)) { - contextMock.when(Context::current).thenReturn(callContext); - when(callContext.wrap(any(Runnable.class))).thenReturn(wrappedRunnable); - doNothing().when(downloader).startDownload(); + doNothing().when(downloader).startDownload(); - downloader.doStart(); + downloader.doStart(); - verify(callContext).wrap(wrappedRunnableCaptor.capture()); - wrappedRunnableCaptor.getValue().run(); - verify(downloader).startDownload(); - } + verify(taskExecutor).execute(runnableCaptor.capture()); + runnableCaptor.getValue().run(); + verify(downloader).startDownload(); } @SneakyThrows diff --git a/ozgcloud-common-lib/src/test/java/de/ozgcloud/common/grpc/GrpcUtilTest.java b/ozgcloud-common-lib/src/test/java/de/ozgcloud/common/grpc/GrpcUtilTest.java index 340d732eefaa5a19cdabea383d9140da0032a261..88e20803b44df1b21e459de4db4d01beae85fce7 100644 --- a/ozgcloud-common-lib/src/test/java/de/ozgcloud/common/grpc/GrpcUtilTest.java +++ b/ozgcloud-common-lib/src/test/java/de/ozgcloud/common/grpc/GrpcUtilTest.java @@ -2,6 +2,7 @@ package de.ozgcloud.common.grpc; import static org.assertj.core.api.Assertions.*; +import com.thedeanda.lorem.LoremIpsum; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Nested; @@ -9,98 +10,184 @@ import org.junit.jupiter.api.Test; import io.grpc.Metadata; +import java.util.UUID; + class GrpcUtilTest { + private static final String KEY_VALUE_BIN = "key_value-bin"; private static final String KEY_VALUE_STRING = "key_value"; private static final String UNKNOWN_KEY_BIN = "unknown_key-bin"; - @DisplayName("Test Grpc Utility methods") + private final Metadata header = new Metadata(); + + @DisplayName("Test creation of MetaData keys") + @Nested + class TestKeyGeneration { + + @Test + void shouldCreateBinaryKey() { + var key = GrpcUtil.createKeyOf(KEY_VALUE_BIN); + + assertThat(key.name()).isEqualTo(KEY_VALUE_BIN); + } + + @Test + void shouldThrowExceptionBecauseOfMissingBinSuffix() { + assertThatExceptionOfType(IllegalArgumentException.class).isThrownBy(() -> GrpcUtil.createKeyOf("key")); + } + + @Test + void shouldCreateAsciiKey() { + var key = GrpcUtil.keyOfString(KEY_VALUE_STRING); + + assertThat(key.name()).isEqualTo(KEY_VALUE_STRING); + } + + @Test + void shouldThrowExceptionBecauseOfBinSuffix() { + assertThatExceptionOfType(IllegalArgumentException.class).isThrownBy(() -> GrpcUtil.keyOfString(KEY_VALUE_BIN)); + } + } + + @DisplayName("Test reading values from the grpc header") + @Nested + class TestReadingFromHeader { + private static final String TEST_VALUE = LoremIpsum.getInstance().getWords(1); + + @BeforeEach + void initMetadata() { + header.put(GrpcUtil.createKeyOf(KEY_VALUE_BIN), TEST_VALUE.getBytes()); + } + + @Test + void shouldReadFromHeader() { + var value = GrpcUtil.getFromHeaders(KEY_VALUE_BIN, header); + + assertThat(value).contains(TEST_VALUE); + } + + @Test + void shouldReturnNullOnUnknownKey() { + var value = GrpcUtil.getFromHeaders(UNKNOWN_KEY_BIN, header); + + assertThat(value).isEmpty(); + } + } + + @DisplayName("Test reading multiple values of a key from the grpc header") + @Nested + class TestReadingCollection { + private static final String TEST_VALUE_1 = LoremIpsum.getInstance().getWords(1); + private static final String TEST_VALUE_2 = LoremIpsum.getInstance().getWords(2); + + @BeforeEach + void initMetadata() { + header.put(GrpcUtil.createKeyOf(KEY_VALUE_BIN), TEST_VALUE_1.getBytes()); + header.put(GrpcUtil.createKeyOf(KEY_VALUE_BIN), TEST_VALUE_2.getBytes()); + } + + @Test + void shouldReadFromHeader() { + var values = GrpcUtil.getList(KEY_VALUE_BIN, header); + + assertThat(values).hasSize(2).contains(TEST_VALUE_1, TEST_VALUE_2); + } + + @Test + void shouldGetEmptyCollectionOnUnknownKey() { + var values = GrpcUtil.getList(UNKNOWN_KEY_BIN, header); + + assertThat(values).isEmpty(); + } + } + @Nested - class TestGrpcUtils { + class TestGetRequestId { - @DisplayName("Test creation of MetaData keys") - @Nested - class TestKeyGeneration { + private static final String REQUEST_ID = UUID.randomUUID().toString(); - @Test - void shouldCreateBinaryKey() { - var key = GrpcUtil.createKeyOf(KEY_VALUE_BIN); + @Test + void shouldReturnRequestId() { + header.put(GrpcUtil.HEADER_KEY_REQUEST_ID, REQUEST_ID.getBytes()); - assertThat(key.name()).isEqualTo(KEY_VALUE_BIN); - } + var result = GrpcUtil.getRequestId(header); - @Test - void shouldThrowExceptionBecauseOfMissingBinSuffix() { - assertThatExceptionOfType(IllegalArgumentException.class).isThrownBy(() -> GrpcUtil.createKeyOf("key")); - } + assertThat(result).contains(REQUEST_ID); + } + } + + @Nested + class TestGetClientName { - @Test - void shouldCreateAsciiKey() { - var key = GrpcUtil.keyOfString(KEY_VALUE_STRING); + private static final String CLIENT_NAME = LoremIpsum.getInstance().getWords(1); - assertThat(key.name()).isEqualTo(KEY_VALUE_STRING); - } + @Test + void shouldReturnClientName() { + header.put(GrpcUtil.HEADER_KEY_CLIENT_NAME, CLIENT_NAME.getBytes()); - @Test - void shouldThrowExceptionBecauseOfBinSuffix() { - assertThatExceptionOfType(IllegalArgumentException.class).isThrownBy(() -> GrpcUtil.keyOfString(KEY_VALUE_BIN)); - } + var result = GrpcUtil.getClientName(header); + + assertThat(result).contains(CLIENT_NAME); } + } - @DisplayName("Test reading values from the grpc header") - @Nested - class TestReadingFromHeader { - private static final String TEST_VALUE = "test-value"; + @Nested + class TestGetUserId { - private Metadata header = new Metadata(); + private static final String USER_ID = LoremIpsum.getInstance().getWords(1); - @BeforeEach - void initMetadata() { - header.put(GrpcUtil.createKeyOf(KEY_VALUE_BIN), TEST_VALUE.getBytes()); - } + @Test + void shouldReturnUserId() { + header.put(GrpcUtil.HEADER_KEY_USER_ID, USER_ID.getBytes()); - @Test - void shouldReadFromHeader() { - var value = GrpcUtil.getFromHeaders(KEY_VALUE_BIN, header); + var result = GrpcUtil.getUserId(header); - assertThat(value).contains(TEST_VALUE); - } + assertThat(result).contains(USER_ID); + } + } + + @Nested + class TestGetUserName { - @Test - void shouldReturnNullOnUnknownKey() { - var value = GrpcUtil.getFromHeaders(UNKNOWN_KEY_BIN, header); + private static final String USER_NAME = LoremIpsum.getInstance().getWords(1); - assertThat(value).isEmpty(); - } + @Test + void shouldReturnUserName() { + header.put(GrpcUtil.HEADER_KEY_USER_NAME, USER_NAME.getBytes()); + + var result = GrpcUtil.getUserName(header); + + assertThat(result).contains(USER_NAME); } + } - @DisplayName("Test reading multiple values of a key from the grpc header") - @Nested - class TestReadingCollection { - private static final String TEST_VALUE_1 = "test-value-1"; - private static final String TEST_VALUE_2 = "test-value-2"; + @Nested + class TestGetAccessLimitedOrgaId { + + private static final String ACCESS_LIMITED_ORGAID = LoremIpsum.getInstance().getWords(1); - private Metadata header = new Metadata(); + @Test + void shouldReturnAccessLimitedOrgaId() { + header.put(GrpcUtil.HEADER_KEY_ACCESS_LIMITED_ORGAID, ACCESS_LIMITED_ORGAID.getBytes()); - @BeforeEach - void initMetadata() { - header.put(GrpcUtil.createKeyOf(KEY_VALUE_BIN), TEST_VALUE_1.getBytes()); - header.put(GrpcUtil.createKeyOf(KEY_VALUE_BIN), TEST_VALUE_2.getBytes()); - } + var result = GrpcUtil.getAccessLimitedOrgaIds(header); + + assertThat(result).containsExactly(ACCESS_LIMITED_ORGAID); + } + } + + @Nested + class TestGetAccessLimited { - @Test - void shouldReadFromHeader() { - var values = GrpcUtil.getCollection(KEY_VALUE_BIN, header); + private static final boolean ACCESS_LIMITED = true; - assertThat(values).hasSize(2).contains(TEST_VALUE_1, TEST_VALUE_2); - } + @Test + void shouldReturnAccessLimited() { + header.put(GrpcUtil.HEADER_KEY_ACCESS_LIMITED, String.valueOf(ACCESS_LIMITED).getBytes()); - @Test - void shouldGetEmptyCollectionOnUnknownKey() { - var values = GrpcUtil.getCollection(UNKNOWN_KEY_BIN, header); + var result = GrpcUtil.getAccessLimited(header); - assertThat(values).isEmpty(); - } + assertThat(result).contains(ACCESS_LIMITED); } } } diff --git a/ozgcloud-common-parent/pom.xml b/ozgcloud-common-parent/pom.xml index 1301486a9fa76008f6ffde0830cfdc2784afcd0a..56428b03a0efdd70ebf8342faf4a91e54f4e3d09 100644 --- a/ozgcloud-common-parent/pom.xml +++ b/ozgcloud-common-parent/pom.xml @@ -393,7 +393,7 @@ <execution> <id>attach-sources</id> <goals> - <goal>jar</goal> + <goal>jar-no-fork</goal> </goals> </execution> </executions>