Skip to content
Snippets Groups Projects
Commit 402ddec6 authored by OZGCloud's avatar OZGCloud
Browse files

OZG-1771 implement route forward-routing

parent 8fcd2a94
No related branches found
No related tags found
No related merge requests found
Showing
with 427 additions and 7 deletions
...@@ -18,7 +18,7 @@ public class FormData { ...@@ -18,7 +18,7 @@ public class FormData {
@NotNull @NotNull
@Builder.Default @Builder.Default
private UUID id = UUID.randomUUID(); private String id = UUID.randomUUID().toString();
private FormHeader header; private FormHeader header;
......
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>de.itvsh.kop.eingangsadapter</groupId>
<artifactId>parent</artifactId>
<version>0.15.0-SNAPSHOT</version>
</parent>
<artifactId>forwarder</artifactId>
<name>Eingangs Adapter - Forwarder</name>
<packaging>jar</packaging>
<properties>
<spring-boot.build-image.imageName>docker.ozg-sh.de/forwarder:build-latest</spring-boot.build-image.imageName>
</properties>
<dependencies>
<!-- own projects -->
<dependency>
<groupId>de.itvsh.kop.eingangsadapter</groupId>
<artifactId>common</artifactId>
</dependency>
<dependency>
<groupId>de.itvsh.kop.eingangsadapter</groupId>
<artifactId>router</artifactId>
</dependency>
<dependency>
<groupId>de.itvsh.ozg.pluto</groupId>
<artifactId>pluto-interface</artifactId>
</dependency>
<!-- spring -->
<dependency>
<groupId>net.devh</groupId>
<artifactId>grpc-server-spring-boot-starter</artifactId>
<version>${grpc.spring-boot-starter.version}</version>
</dependency>
<!-- Tools -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
</dependency>
<!-- Dev -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<!-- Test -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
\ No newline at end of file
package de.itvsh.kop.eingangsadapter.forwarder;
import java.util.Optional;
import lombok.Builder;
import lombok.Getter;
@Getter
@Builder
public class RouteCriteria {
private Optional<String> gemeindeSchluessel;
private Optional<String> webserviceUrl;
private Optional<String> organisationseinheitenId;
}
package de.itvsh.kop.eingangsadapter.forwarder;
import java.util.Optional;
import org.apache.commons.lang3.StringUtils;
import org.mapstruct.Mapper;
import de.itvsh.kop.eingangsadapter.forwarding.GrpcRouteCriteria;
@Mapper
interface RouteCriteriaMapper {
RouteCriteria fromGrpc(GrpcRouteCriteria grpcRouteCriteria);
default Optional<String> wrapWithOptional(String val) {
return Optional.ofNullable(StringUtils.trimToNull(val));
}
}
package de.itvsh.kop.eingangsadapter.forwarder;
import org.springframework.beans.factory.annotation.Autowired;
import de.itvsh.kop.eingangsadapter.forwarding.GrpcRouteForwardingRequest;
import de.itvsh.kop.eingangsadapter.forwarding.GrpcRouteForwardingResponse;
import de.itvsh.kop.eingangsadapter.router.GrpcEingangMapper;
import de.itvsh.kop.eingangsadapter.router.GrpcFormDataMapper;
import io.grpc.stub.StreamObserver;
import net.devh.boot.grpc.server.service.GrpcService;
@GrpcService
public class RouteForwardingGrpcService extends RouteForwardingServiceGrpc.RouteForwardingServiceImplBase {
@Autowired
private RouteForwardingService service;
@Autowired
private RouteCriteriaMapper criteriaMapper;
@Autowired
private GrpcEingangMapper eingangMapper;
@Autowired
private GrpcFormDataMapper formDataMapper;
@Override
public void routeForwarding(GrpcRouteForwardingRequest request, StreamObserver<GrpcRouteForwardingResponse> responseObserver) {
service.route(criteriaMapper.fromGrpc(request.getRouteCriteria()), formDataMapper.mapFromFormData(request.getE));
}
}
package de.itvsh.kop.eingangsadapter.forwarder;
import org.springframework.stereotype.Service;
import de.itvsh.kop.eingangsadapter.common.formdata.FormData;
@Service
class RouteForwardingService {
public void route(RouteCriteria criteria, FormData formData) {
//FIXME implement me
}
}
package de.itvsh.kop.eingangsadapter.forwarder;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
import de.itvsh.kop.eingangsadapter.Application;
@SpringBootTest(classes = Application.class)
class ForwarderApplicationTest {
@Test
void contextLoads() { // NOSONAR nothing to check - it it starts it is fine
}
}
package de.itvsh.kop.eingangsadapter.forwarder;
import de.itvsh.kop.eingangsadapter.forwarding.GrpcRouteForwardingRequest;
public class GrpcRouteForwardingRequestTestFactory {
public static GrpcRouteForwardingRequest create() {
return createBuilder().build();
}
public static GrpcRouteForwardingRequest.Builder createBuilder() {
return GrpcRouteForwardingRequest.newBuilder()
.setRouteCriteria(RouteCriteriaTestFactory.createGrpc());
}
}
package de.itvsh.kop.eingangsadapter.forwarder;
import java.util.Optional;
import de.itvsh.kop.eingangsadapter.forwarding.GrpcRouteCriteria;
public class RouteCriteriaTestFactory {
public static final String GEMEINDE_SCHLUSSEL = "0815";
public static final String WEBSERVICE_URL = "http://nimmerland.ozg-sh.de/ws";
public static final String ORGANISATIONSEINHEITEN_ID = "4711";
public static RouteCriteria create() {
return createBuilder().build();
}
public static RouteCriteria.RouteCriteriaBuilder createBuilder() {
return RouteCriteria.builder()
.gemeindeSchluessel(Optional.of(GEMEINDE_SCHLUSSEL))
.webserviceUrl(Optional.of(WEBSERVICE_URL))
.organisationseinheitenId(Optional.of(ORGANISATIONSEINHEITEN_ID));
}
public static GrpcRouteCriteria createGrpc() {
return createGrpcBuilder().build();
}
public static GrpcRouteCriteria.Builder createGrpcBuilder() {
return GrpcRouteCriteria.newBuilder()
.setGemeindeSchluessel(GEMEINDE_SCHLUSSEL)
.setWebserviceUrl(WEBSERVICE_URL)
.setOrganisationseinheitenId(ORGANISATIONSEINHEITEN_ID);
}
}
package de.itvsh.kop.eingangsadapter.forwarder;
import static org.assertj.core.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.mapstruct.factory.Mappers;
import org.mockito.ArgumentCaptor;
import org.mockito.Captor;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.Spy;
import de.itvsh.kop.eingangsadapter.forwarding.GrpcRouteForwardingResponse;
import de.itvsh.kop.eingangsadapter.router.GrpcEingangMapper;
import de.itvsh.kop.eingangsadapter.router.GrpcFormDataMapper;
import io.grpc.stub.StreamObserver;
class RouteForwardingGrpcServiceTest {
@InjectMocks
private RouteForwardingGrpcService service;
@Mock
private StreamObserver<GrpcRouteForwardingResponse> responseObserver;
@Mock
private RouteForwardingService routeService;
@Spy
private RouteCriteriaMapper criteriaMapper = Mappers.getMapper(RouteCriteriaMapper.class);
@Spy
private GrpcEingangMapper eingangMapper; = Mappers.getMapper(GrpcEingangMapper.class);
@Nested
class TestRouteForwarding {
@Captor
private ArgumentCaptor<RouteCriteria> criteriaCaptor;
@Test
void shouldCallService() {
service.routeForwarding(GrpcRouteForwardingRequestTestFactory.create(), responseObserver);
verify(routeService).route(any(), any());
}
@Test
void shouldHaveRouteCriteria() {
service.routeForwarding(GrpcRouteForwardingRequestTestFactory.create(), responseObserver);
verify(routeService).route(criteriaCaptor.capture(), any());
assertThat(criteriaCaptor.getValue()).usingRecursiveComparison().isEqualTo(RouteCriteriaTestFactory.create());
}
@Test
void shouldHaveFormData() {
service.routeForwarding(GrpcRouteForwardingRequestTestFactory.create(), responseObserver);
verify(routeService).route(any(), notNull());
verify(formDataMapper).mapToSubForms(any());
}
}
}
org.mockito.junit.jupiter.MockitoExtension
\ No newline at end of file
spring:
profiles:
active:
- itcase
logging:
level:
ROOT: ERROR
grpc:
client:
pluto-nf:
address: static://127.0.0.1:9090
negotiationType: PLAINTEXT
kop:
adapter:
routingStrategy: SINGLE
targetPlutoName: nf
\ No newline at end of file
junit.jupiter.extensions.autodetection.enabled = true
\ No newline at end of file
...@@ -5,7 +5,6 @@ import java.io.InputStream; ...@@ -5,7 +5,6 @@ import java.io.InputStream;
import java.util.Arrays; import java.util.Arrays;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.UUID;
import java.util.function.Supplier; import java.util.function.Supplier;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import java.util.stream.Stream; import java.util.stream.Stream;
...@@ -60,7 +59,6 @@ class FileReaderAntragDirectoryParser { ...@@ -60,7 +59,6 @@ class FileReaderAntragDirectoryParser {
Map<String, Object> formDataMap = xmlToJavaMapsMapper.mapXmlToJavaMaps(document); Map<String, Object> formDataMap = xmlToJavaMapsMapper.mapXmlToJavaMaps(document);
return FormData.builder() return FormData.builder()
.id(UUID.randomUUID())
.header(formHeaderMapper.map(document)) .header(formHeaderMapper.map(document))
.antragsteller(antragstellerMapper.mapToAntragsteller(formDataMap)) .antragsteller(antragstellerMapper.mapToAntragsteller(formDataMap))
.zustaendigeStelle(zustaendigeStelleMapper.map(formDataMap)) .zustaendigeStelle(zustaendigeStelleMapper.map(formDataMap))
......
...@@ -3,7 +3,6 @@ package de.itvsh.kop.eingangsadapter.intelliform; ...@@ -3,7 +3,6 @@ package de.itvsh.kop.eingangsadapter.intelliform;
import java.io.InputStream; import java.io.InputStream;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.UUID;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
...@@ -52,7 +51,6 @@ class FormDataMapper { ...@@ -52,7 +51,6 @@ class FormDataMapper {
formDataFiles = attachmentsContentAdder.addContentToAttachments(formDataFiles, depositRequestFiles); formDataFiles = attachmentsContentAdder.addContentToAttachments(formDataFiles, depositRequestFiles);
return FormData.builder() return FormData.builder()
.id(UUID.randomUUID())
.header(formHeaderMapper.map(document)) .header(formHeaderMapper.map(document))
.antragsteller(antragstellerMapper.mapToAntragsteller(formDataMap)) .antragsteller(antragstellerMapper.mapToAntragsteller(formDataMap))
.zustaendigeStelle(zustaendigeStelleMapper.map(formDataMap)) .zustaendigeStelle(zustaendigeStelleMapper.map(formDataMap))
......
...@@ -21,6 +21,7 @@ ...@@ -21,6 +21,7 @@
<module>formsolutions-adapter</module> <module>formsolutions-adapter</module>
<module>intelliform-adapter</module> <module>intelliform-adapter</module>
<module>router</module> <module>router</module>
<module>forwarder</module>
</modules> </modules>
<properties> <properties>
......
...@@ -33,6 +33,13 @@ ...@@ -33,6 +33,13 @@
<optional>true</optional> <optional>true</optional>
</dependency> </dependency>
<!-- Tools -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
</dependency>
<!-- Test --> <!-- Test -->
<dependency> <dependency>
<groupId>org.springframework.boot</groupId> <groupId>org.springframework.boot</groupId>
......
...@@ -25,7 +25,7 @@ import de.itvsh.ozg.pluto.vorgang.GrpcZustaendigeStelle; ...@@ -25,7 +25,7 @@ import de.itvsh.ozg.pluto.vorgang.GrpcZustaendigeStelle;
nullValueCheckStrategy = NullValueCheckStrategy.ALWAYS, // nullValueCheckStrategy = NullValueCheckStrategy.ALWAYS, //
collectionMappingStrategy = CollectionMappingStrategy.ADDER_PREFERRED, // collectionMappingStrategy = CollectionMappingStrategy.ADDER_PREFERRED, //
uses = GrpcFormDataMapper.class) uses = GrpcFormDataMapper.class)
interface GrpcEingangMapper { public interface GrpcEingangMapper {
@Mapping(source = "antragsteller.data", target = "antragsteller.otherData") @Mapping(source = "antragsteller.data", target = "antragsteller.otherData")
@Mapping(source = "attachments", target = "attachmentsList") @Mapping(source = "attachments", target = "attachmentsList")
...@@ -51,4 +51,11 @@ interface GrpcEingangMapper { ...@@ -51,4 +51,11 @@ interface GrpcEingangMapper {
return id.toString(); return id.toString();
} }
// FIXME map representations and attachments
@Mapping(target = "attachment", ignore = true)
@Mapping(target = "attachments", ignore = true)
@Mapping(target = "representation", ignore = true)
@Mapping(target = "representations", ignore = true)
FormData toFormData(GrpcEingang eingang);
} }
package de.itvsh.kop.eingangsadapter.router; package de.itvsh.kop.eingangsadapter.router;
import java.util.Collection;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Map.Entry; import java.util.Map.Entry;
import java.util.Objects;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import org.apache.commons.lang3.tuple.Pair;
import org.mapstruct.CollectionMappingStrategy; import org.mapstruct.CollectionMappingStrategy;
import org.mapstruct.Mapper; import org.mapstruct.Mapper;
import org.mapstruct.NullValueCheckStrategy; import org.mapstruct.NullValueCheckStrategy;
...@@ -20,7 +25,7 @@ import de.itvsh.ozg.pluto.vorgang.GrpcSubForm; ...@@ -20,7 +25,7 @@ import de.itvsh.ozg.pluto.vorgang.GrpcSubForm;
nullValuePropertyMappingStrategy = NullValuePropertyMappingStrategy.IGNORE, // nullValuePropertyMappingStrategy = NullValuePropertyMappingStrategy.IGNORE, //
nullValueCheckStrategy = NullValueCheckStrategy.ALWAYS, // nullValueCheckStrategy = NullValueCheckStrategy.ALWAYS, //
collectionMappingStrategy = CollectionMappingStrategy.ADDER_PREFERRED) collectionMappingStrategy = CollectionMappingStrategy.ADDER_PREFERRED)
interface GrpcFormDataMapper { public interface GrpcFormDataMapper {
default GrpcFormData mapFormData(Map<String, Object> formData) { default GrpcFormData mapFormData(Map<String, Object> formData) {
return GrpcFormData.newBuilder() return GrpcFormData.newBuilder()
...@@ -89,4 +94,92 @@ interface GrpcFormDataMapper { ...@@ -89,4 +94,92 @@ interface GrpcFormDataMapper {
default GrpcFormField mapToField(String name, String value) { default GrpcFormField mapToField(String name, String value) {
return GrpcFormField.newBuilder().setName(name).setValue(value).build(); return GrpcFormField.newBuilder().setName(name).setValue(value).build();
} }
// TODO copied from de.itvsh.ozg.pluto.vorgang.GrpcFormDataMapper
// move to mapper util lib (OZG-1517)
default Map<String, Object> mapFromFormData(GrpcFormData formData) {
Map<String, Object> result = new HashMap<>();
result.putAll(mapSubFormFields(formData.getFieldList()));
result.putAll(mapFormData(formData.getFormList()));
return result;
}
default Map<String, Object> mapFormData(List<GrpcSubForm> subForms) {
return subForms.stream().map(subForm -> Pair.of(subForm.getTitle(), mapSubForm(subForm)))
.collect(HashMap<String, Object>::new, this::pairAccumulator, this::combiner);
}
private Map<String, Object> pairAccumulator(Map<String, Object> map, Pair<String, Map<String, Object>> pair) {
return addToMap(map, pair.getLeft(), pair.getRight());
}
default Map<String, Object> mapSubForm(GrpcSubForm subForm) {
Map<String, Object> result = new HashMap<>();
result.putAll(mapSubFormFields(subForm.getFieldList()));
result.putAll(mapFormData(subForm.getSubFormList()));
return result;
}
default Map<String, Object> mapSubFormFields(List<GrpcFormField> fields) {
return fields.stream().collect(HashMap<String, Object>::new, this::accumulator, this::combiner);
}
private Map<String, Object> accumulator(Map<String, Object> map, GrpcFormField field) {
return addToMap(map, field.getName(), field.getValue());
}
default Map<String, Object> combiner(Map<String, Object> map1, Map<String, Object> map2) {
for (Entry<String, Object> entry : map2.entrySet()) {
addToMap(map1, entry.getKey(), entry.getValue());
}
return map1;
}
@SuppressWarnings("unchecked")
private Map<String, Object> addToMap(Map<String, Object> map, String name, Object value) {
var valueInMap = map.get(name);
if (Objects.isNull(valueInMap)) {
map.put(name, value);
} else {
if (value instanceof Collection) {
addCollectionValue(map, name, (Collection<Object>) value);
} else {
addNonCollectionValue(map, name, value);
}
}
return map;
}
@SuppressWarnings("unchecked")
private Map<String, Object> addCollectionValue(Map<String, Object> map, String name, Collection<Object> value) {
var valueInMap = map.get(name);
var newList = new LinkedList<Object>();
if (valueInMap instanceof Collection) {
newList.addAll((Collection<? extends Object>) valueInMap);
newList.addAll(value);
} else {
newList.add(valueInMap);
newList.addAll(value);
}
map.put(name, newList);
return map;
}
@SuppressWarnings("unchecked")
private Map<String, Object> addNonCollectionValue(Map<String, Object> map, String name, Object value) {
var valueInMap = map.get(name);
if (valueInMap instanceof Collection) {
var newList = new LinkedList<>((Collection<Object>) valueInMap);
newList.add(value);
map.put(name, newList);
} else {
map.put(name, new LinkedList<>(List.of(valueInMap, value)));
}
return map;
}
} }
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment