Skip to content
Snippets Groups Projects
Commit 8f10b92a authored by OZGCloud's avatar OZGCloud
Browse files

Merge pull request 'OZG-6751-InfoManager-code-cleanup' (#35) from...

Merge pull request 'OZG-6751-InfoManager-code-cleanup' (#35) from OZG-6751-InfoManager-code-cleanup into master

Reviewed-on: https://git.ozg-sh.de/ozgcloud-app/info-manager/pulls/35


Reviewed-by: default avatarOZGCloud <ozgcloud@mgm-tp.com>
parents 20ab96bc 89d96bd0
Branches
Tags
No related merge requests found
Showing
with 61 additions and 359 deletions
......@@ -8,7 +8,7 @@ For further reference, please consider the following sections:
* [Spring Boot Gradle Plugin Reference Guide](https://docs.spring.io/spring-boot/docs/current/gradle-plugin/reference/htmlsingle/)
* [Create an OCI image](https://docs.spring.io/spring-boot/docs/3.1.3/maven-plugin/reference/html/#build-image)
* [gRPC](https://grpc.io/)
* [Spring RestClient](https://docs.spring.io/spring-framework/reference/integration/rest-clients.html)
* [Spring Boot Actuator](https://docs.spring.io/spring-boot/docs/3.1.3/reference/htmlsingle/index.html#actuator)
* [Spring Data MongoDB](https://docs.spring.io/spring-data/mongodb/docs/current/reference/html/)
* [Spring Boot DevTools](https://docs.spring.io/spring-boot/docs/3.1.3/reference/htmlsingle/index.html#using.devtools)
......@@ -39,3 +39,7 @@ Run it from commandline use:
```
at the info-manager root directory
### Releasing
See [Release Antragsraum](https://git.ozg-sh.de/ozgcloud-doc/dokumentation/src/branch/master/Operations/Release-Antragsraum.md)
\ No newline at end of file
......@@ -65,12 +65,6 @@
<version>${info-manager-interface.version}</version>
</dependency>
<dependency>
<groupId>net.devh</groupId>
<artifactId>grpc-client-spring-boot-starter</artifactId>
<version>${net-devh-grpc.version}</version>
</dependency>
<dependency>
<groupId>net.devh</groupId>
<artifactId>grpc-server-spring-boot-starter</artifactId>
......@@ -156,6 +150,13 @@
<version>${ozgcloud-starter.version}</version>
</dependency>
<dependency>
<groupId>net.devh</groupId>
<artifactId>grpc-client-spring-boot-starter</artifactId>
<version>${net-devh-grpc.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
......
......@@ -23,27 +23,12 @@
package de.ozgcloud.info;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import de.ozgcloud.info.common.CallBeanFactoryPostProcessor;
import de.ozgcloud.info.common.CallScope;
@SpringBootApplication
public class InfoManagerApplication {
public static void main(String[] args) {
SpringApplication.run(InfoManagerApplication.class, args);
}
@Bean
public CallScope callScope() {
return new CallScope();
}
@Bean
public static BeanFactoryPostProcessor beanFactoryPostProcessor(CallScope callScope) {
return new CallBeanFactoryPostProcessor(callScope);
}
}
/*
* Copyright (c) 2023-2024.
* 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.info;
import org.springframework.context.annotation.Configuration;
import lombok.RequiredArgsConstructor;
import lombok.extern.log4j.Log4j2;
@Configuration
@Log4j2
@RequiredArgsConstructor
public class SecurityConfiguration {
}
/*
* Copyright (c) 2023-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.info.common;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import lombok.RequiredArgsConstructor;
@RequiredArgsConstructor
public class CallBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
private final CallScope callScope;
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
beanFactory.registerScope(CallScope.SCOPE_NAME, callScope);
}
}
/*
* Copyright (c) 2023-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.info.common;
import io.grpc.Metadata;
import io.grpc.ServerCall;
import io.grpc.ServerCallHandler;
import io.grpc.ServerInterceptor;
import lombok.NonNull;
import lombok.RequiredArgsConstructor;
import lombok.extern.log4j.Log4j2;
import net.devh.boot.grpc.server.interceptor.GrpcGlobalServerInterceptor;
@Log4j2
@GrpcGlobalServerInterceptor
@RequiredArgsConstructor
public class CallContextAttachingInterceptor implements ServerInterceptor {
private final @NonNull ContextService contextService;
@Override
public <ReqT, RespT> ServerCall.Listener<ReqT> interceptCall(ServerCall<ReqT, RespT> call, Metadata headers,
ServerCallHandler<ReqT, RespT> next) {
contextService.readMetadata(headers);
LOG.debug("Got metadata: {}", headers);
return next.startCall(call, headers);
}
}
/*
* Copyright (c) 2023-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.info.common;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import org.springframework.beans.factory.ObjectFactory;
import org.springframework.beans.factory.config.Scope;
import org.springframework.core.NamedInheritableThreadLocal;
import lombok.NonNull;
import lombok.extern.log4j.Log4j2;
@Log4j2
public class CallScope implements Scope {
public static final String SCOPE_NAME = "call";
static final ThreadLocal<Map<String, Object>> scopedObjectsHolder = new NamedInheritableThreadLocal<>("Call Context");
static final ThreadLocal<Map<String, Runnable>> destructionCallbacksHolder = new NamedInheritableThreadLocal<>(
"Call Context Destruction Callbacks");
public void startScope() {
LOG.debug("START Call-Scope");
scopedObjectsHolder.set(new ConcurrentHashMap<>());
destructionCallbacksHolder.set(new ConcurrentHashMap<>());
}
public void endScope() {
scopedObjectsHolder.remove();
callAllDestructionCallbacks();
destructionCallbacksHolder.remove();
LOG.debug("END Call-Scope");
}
void callAllDestructionCallbacks() {
destructionCallbacksHolder.get().values().forEach(Runnable::run);
}
@Override
public @NonNull Object get(@NonNull String name, @NonNull ObjectFactory<?> objectFactory) {
if (!scopedObjectsHolder.get().containsKey(name)) {
scopedObjectsHolder.get().put(name, objectFactory.getObject());
}
return scopedObjectsHolder.get().get(name);
}
@Override
public Object remove(@NonNull String name) {
destructionCallbacksHolder.get().remove(name);
return scopedObjectsHolder.get().remove(name);
}
@Override
public void registerDestructionCallback(@NonNull String name, @NonNull Runnable callback) {
destructionCallbacksHolder.get().put(name, callback);
}
@Override
public Object resolveContextualObject(@NonNull String key) {
return scopedObjectsHolder.get().get(key);
}
@Override
public String getConversationId() {
return Thread.currentThread().getName();
}
}
/*
* Copyright (c) 2023-2024.
* 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.info.common;
import java.util.Optional;
import org.springframework.stereotype.Service;
import io.grpc.Metadata;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import lombok.extern.log4j.Log4j2;
@Getter
@Log4j2
@Service
@RequiredArgsConstructor
public class ContextService {
public static final String KEY_CLIENT_NAME = "CLIENT_NAME-bin";
public static final String KEY_REQUEST_ID = "REQUEST_ID-bin";
public static final String KEY_AUTHENTICATION_ID = "AUTHENTICATION-bin";
public static final String KEY_JWT_TOKEN = "JWT_TOKEN-bin";
private RequestAttributes requestAttributes;
void readMetadata(Metadata headers) {
var requestAttributesBuilder = RequestAttributes.builder();
getRequestId(headers).ifPresent(id -> requestAttributesBuilder.requestId(new String(id)));
getClientName(headers).ifPresent(name -> requestAttributesBuilder.clientName(new String(name)));
getJwtToken(headers).ifPresent(token -> requestAttributesBuilder.jwtToken(new String(token)));
getAuthentication(headers).ifPresent(saml -> requestAttributesBuilder.samlToken(new String(saml)));
requestAttributes = requestAttributesBuilder.build();
}
Optional<byte[]> getRequestId(Metadata headers) {
return Optional.ofNullable(headers.get(ContextService.createKeyOf(ContextService.KEY_REQUEST_ID)));
}
Optional<byte[]> getClientName(Metadata headers) {
return Optional.ofNullable(headers.get(ContextService.createKeyOf(ContextService.KEY_CLIENT_NAME)));
}
Optional<byte[]> getAuthentication(Metadata headers) {
return Optional.ofNullable(headers.get(ContextService.createKeyOf(ContextService.KEY_AUTHENTICATION_ID)));
}
Optional<byte[]> getJwtToken(Metadata headers) {
return Optional.ofNullable(headers.get(ContextService.createKeyOf(ContextService.KEY_JWT_TOKEN)));
}
static Metadata.Key<byte[]> createKeyOf(String key) {
return Metadata.Key.of(key, Metadata.BINARY_BYTE_MARSHALLER);
}
}
......@@ -18,12 +18,11 @@
* unter der Lizenz sind dem Lizenztext zu entnehmen.
*/
package de.ozgcloud.info.nachricht;
package de.ozgcloud.info.common;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.Size;
import org.bson.types.ObjectId;
import org.springframework.data.annotation.Id;
import org.springframework.data.mongodb.core.index.CompoundIndex;
import org.springframework.data.mongodb.core.mapping.Document;
......@@ -39,7 +38,7 @@ import lombok.Setter;
@Setter
public class NachrichtEvent {
@Id
private ObjectId id;
private String id;
@NotBlank(message = "Postfach id is missing")
@Size(max = 128, message = "Invalid PostfachId")
......
......@@ -18,7 +18,7 @@
* unter der Lizenz sind dem Lizenztext zu entnehmen.
*/
package de.ozgcloud.info.infomanager;
package de.ozgcloud.info.information;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;
......@@ -30,5 +30,5 @@ import lombok.Getter;
@ConfigurationProperties(prefix = InfoManagerProperties.PREFIX)
public class InfoManagerProperties {
static final String PREFIX = "ozgcloud.infomanager";
private String postfachIdKeyName = "postkorbhandle";
private final String postfachIdKeyName = "postkorbhandle";
}
......@@ -18,7 +18,7 @@
* unter der Lizenz sind dem Lizenztext zu entnehmen.
*/
package de.ozgcloud.info.infomanager;
package de.ozgcloud.info.information;
import java.util.NoSuchElementException;
......
......@@ -18,10 +18,10 @@
* unter der Lizenz sind dem Lizenztext zu entnehmen.
*/
package de.ozgcloud.info.infomanager;
package de.ozgcloud.info.information;
import de.ozgcloud.info.GrpcInformationNachricht;
import de.ozgcloud.info.nachricht.NachrichtEvent;
import de.ozgcloud.info.common.NachrichtEvent;
import lombok.AccessLevel;
import lombok.NoArgsConstructor;
......@@ -29,7 +29,7 @@ import lombok.NoArgsConstructor;
class InformationMapper {
static GrpcInformationNachricht fromNachrichtEvent(NachrichtEvent nachrichtEvent) {
return GrpcInformationNachricht.newBuilder()
.setId(nachrichtEvent.getId().toHexString())
.setId(nachrichtEvent.getId())
.setPostfachId(nachrichtEvent.getPostfachId())
.setOzgCloudAddress(nachrichtEvent.getNachrichtenListUrl())
.build();
......
......@@ -18,11 +18,9 @@
* unter der Lizenz sind dem Lizenztext zu entnehmen.
*/
package de.ozgcloud.info.information;
package de.ozgcloud.info.infomanager;
import de.ozgcloud.info.common.NachrichtEvent;
import de.ozgcloud.info.nachricht.NachrichtEvent;
import org.bson.types.ObjectId;
interface InformationRepository extends ReadOnlyRepository<NachrichtEvent, ObjectId> {
interface InformationRepository extends ReadOnlyRepository<NachrichtEvent, String> {
}
......@@ -18,14 +18,13 @@
* unter der Lizenz sind dem Lizenztext zu entnehmen.
*/
package de.ozgcloud.info.infomanager;
package de.ozgcloud.info.information;
import java.util.List;
import org.bson.types.ObjectId;
import org.springframework.stereotype.Service;
import de.ozgcloud.info.nachricht.NachrichtEvent;
import de.ozgcloud.info.common.NachrichtEvent;
import lombok.RequiredArgsConstructor;
@Service
......@@ -34,7 +33,7 @@ class InformationService {
private final InformationRepository repository;
NachrichtEvent getInformationById(String id) {
return repository.findById(new ObjectId(id)).orElseThrow();
return repository.findById(id).orElseThrow();
}
List<NachrichtEvent> getInformationOfPostfach(String postfachId) {
......
......@@ -18,10 +18,10 @@
* unter der Lizenz sind dem Lizenztext zu entnehmen.
*/
package de.ozgcloud.info.infomanager;
package de.ozgcloud.info.information;
import java.util.List;
import org.springframework.data.repository.CrudRepository;
import org.springframework.data.repository.NoRepositoryBean;
......
......@@ -20,9 +20,14 @@
package de.ozgcloud.info.nachricht;
import java.util.Set;
import jakarta.validation.ConstraintViolation;
import jakarta.validation.ConstraintViolationException;
import jakarta.validation.Validator;
import de.ozgcloud.info.common.InvalidNachrichtenListUrlException;
import de.ozgcloud.info.common.NachrichtEvent;
import io.grpc.Status;
import io.grpc.stub.StreamObserver;
import lombok.RequiredArgsConstructor;
......@@ -30,11 +35,12 @@ import net.devh.boot.grpc.server.service.GrpcService;
@GrpcService
@RequiredArgsConstructor
public class NachrichtenGrpcService extends NachrichtServiceGrpc.NachrichtServiceImplBase {
public class NachrichtGrpcService extends NachrichtServiceGrpc.NachrichtServiceImplBase {
static final String STATUS_OK = "ok";
private final NachrichtenService nachrichtService;
private final NachrichtenMapper nachrichtenMapper;
private final NachrichtService nachrichtService;
private final NachrichtMapper nachrichtenMapper;
private final Validator validator;
@Override
public void saveNewNachricht(GrpcNewNachrichtRequest request, StreamObserver<GrpcNewNachrichtReply> responseObserver) {
......@@ -49,7 +55,20 @@ public class NachrichtenGrpcService extends NachrichtServiceGrpc.NachrichtServic
}
private void saveNachricht(GrpcNewNachrichtRequest request) {
nachrichtService.save(nachrichtenMapper.fromGrpcNachricht(request.getNachricht()));
var nachricht = nachrichtenMapper.fromGrpcNachricht(request.getNachricht());
if (isValid(nachricht)) {
nachrichtService.save(nachricht);
}
}
private boolean isValid(NachrichtEvent nachrichtEvent) {
Set<ConstraintViolation<NachrichtEvent>> violations = validator.validate(nachrichtEvent);
if (!violations.isEmpty()) {
throw new ConstraintViolationException(violations);
}
return true;
}
@Override
......
......@@ -25,11 +25,12 @@ import org.springframework.core.env.Profiles;
import org.springframework.stereotype.Component;
import de.ozgcloud.info.common.InvalidNachrichtenListUrlException;
import de.ozgcloud.info.common.NachrichtEvent;
import lombok.RequiredArgsConstructor;
@Component
@RequiredArgsConstructor
class NachrichtenMapper {
class NachrichtMapper {
static final String LOCAL_PROFILE = "local";
private static final String NACHRICHTEN_LIST_URL_REGEX = "^[A-Za-z\\d-]+(\\.[A-Za-z\\d-]+){0,512}:\\d{1,5}$";
static final String NACHRICHTEN_LIST_URL_FORMAT = "dns:///%s";
......
......@@ -25,7 +25,9 @@ import java.util.Optional;
import org.bson.types.ObjectId;
import org.springframework.data.mongodb.repository.MongoRepository;
interface NachrichtenRepository extends MongoRepository<NachrichtEvent, ObjectId> {
import de.ozgcloud.info.common.NachrichtEvent;
interface NachrichtRepository extends MongoRepository<NachrichtEvent, ObjectId> {
Optional<NachrichtEvent> findByPostfachIdAndNachrichtenListUrl(String postfachId, String nachrichtenListUrl);
void deleteByPostfachIdAndNachrichtenListUrl(String postfachId, String nachrichtenListUrl);
......
......@@ -22,12 +22,13 @@ package de.ozgcloud.info.nachricht;
import org.springframework.stereotype.Service;
import de.ozgcloud.info.common.NachrichtEvent;
import lombok.RequiredArgsConstructor;
@Service
@RequiredArgsConstructor
class NachrichtenService {
private final NachrichtenRepository repository;
class NachrichtService {
private final NachrichtRepository repository;
void save(NachrichtEvent nachrichtEvent) {
if (!nachrichtEventPresent(nachrichtEvent)) {
......
......@@ -22,33 +22,11 @@
*/
package de.ozgcloud.info;
import static org.assertj.core.api.Assertions.*;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.Spy;
import org.mockito.junit.jupiter.MockitoExtension;
import de.ozgcloud.info.common.CallScope;
@ExtendWith(MockitoExtension.class)
class InfoManagerApplicationTest {
@Spy
@InjectMocks
private InfoManagerApplication application;
@Test
void shouldCreateCallScope() {
var callScope = application.callScope();
assertThat(callScope).isNotNull();
}
@Test
void shouldCreateBeanFactoryPostProcessor() {
var beanProcessor = InfoManagerApplication.beanFactoryPostProcessor(new CallScope());
assertThat(beanProcessor).isNotNull();
}
}
\ No newline at end of file
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment