diff --git a/common/pom.xml b/common/pom.xml index 7bcf1e69a7d60e3ba3f330eb38d46ddb401ff291..8c856ccd354a3ad583f589207700677fc4358541 100644 --- a/common/pom.xml +++ b/common/pom.xml @@ -31,7 +31,7 @@ <parent> <groupId>de.ozgcloud.eingang</groupId> <artifactId>eingang-manager</artifactId> - <version>2.13.0-SNAPSHOT</version> + <version>2.15.0-SNAPSHOT</version> <relativePath>../</relativePath> </parent> <artifactId>common</artifactId> diff --git a/common/src/main/java/de/ozgcloud/eingang/EingangAspectPointcuts.java b/common/src/main/java/de/ozgcloud/eingang/EingangAspectPointcuts.java new file mode 100644 index 0000000000000000000000000000000000000000..5a4eafc31fba2d3e5913e47c6e41207412276d10 --- /dev/null +++ b/common/src/main/java/de/ozgcloud/eingang/EingangAspectPointcuts.java @@ -0,0 +1,26 @@ +package de.ozgcloud.eingang; + +import org.aspectj.lang.annotation.Pointcut; + +public class EingangAspectPointcuts { + + @Pointcut("execution(public * *(..))") + void anyPublicMethods() { + // aspect pointcut - no implementation needed + } + + @Pointcut("within(de.ozgcloud..*)") + void anythingInOzgCloud() { + // aspect pointcut - no implementation needed + } + + @Pointcut("anyPublicMethods() && anythingInOzgCloud()") + void anyPublicMethodInOzgCloud() { + // aspect pointcut - no implementation needed + } + + @Pointcut("anyPublicMethodInOzgCloud() && target(de.ozgcloud.eingang.semantik.enginebased.EngineBasedMapper)") + void publicMethodInEngineBasedMapper() { + // aspect pointcut - no implementation needed + } +} diff --git a/common/src/main/java/de/ozgcloud/eingang/EingangLoggingAspect.java b/common/src/main/java/de/ozgcloud/eingang/EingangLoggingAspect.java new file mode 100644 index 0000000000000000000000000000000000000000..584acf3a329f1b2e79b62184c861b1b79f1e783c --- /dev/null +++ b/common/src/main/java/de/ozgcloud/eingang/EingangLoggingAspect.java @@ -0,0 +1,25 @@ +package de.ozgcloud.eingang; + +import org.aspectj.lang.JoinPoint; +import org.aspectj.lang.annotation.AfterReturning; +import org.aspectj.lang.annotation.Aspect; +import org.aspectj.lang.annotation.Before; +import org.springframework.stereotype.Component; + +import de.ozgcloud.common.logging.AspectLoggingUtils; + +@Aspect +@Component +public class EingangLoggingAspect extends EingangAspectPointcuts { + + @Before("publicMethodInEngineBasedMapper()") + public void onEngineBasedMapper(JoinPoint joinPoint) { + AspectLoggingUtils.log(joinPoint); + } + + @AfterReturning(pointcut = "publicMethodInEngineBasedMapper()", returning = "returnValue") + public void afterServiceMethod(JoinPoint joinPoint, Object returnValue) { + AspectLoggingUtils.logReturnValue(joinPoint, returnValue); + } + +} diff --git a/common/src/main/java/de/ozgcloud/eingang/common/formdata/FormData.java b/common/src/main/java/de/ozgcloud/eingang/common/formdata/FormData.java index 474be54dfd8c56eb60f5d9b2fb535742273f0fe8..26ff0c888125264f81d9d31ea6c8ba5ae8381384 100644 --- a/common/src/main/java/de/ozgcloud/eingang/common/formdata/FormData.java +++ b/common/src/main/java/de/ozgcloud/eingang/common/formdata/FormData.java @@ -48,7 +48,8 @@ public class FormData { @Builder.Default private FormHeader header = FormHeader.builder().build(); - private ZustaendigeStelle zustaendigeStelle; + @Singular + private List<ZustaendigeStelle> zustaendigeStelles; @ToString.Exclude private Antragsteller antragsteller; @ToString.Exclude @@ -63,16 +64,21 @@ public class FormData { @Singular private List<IncomingFile> representations; - private FormDataControl control; + @Builder.Default + private FormDataControl control = FormDataControl.builder().build(); @Getter - @Builder + @Builder(toBuilder = true) + @ToString public static class FormDataControl { - private Optional<Representations> representations; + @Builder.Default + private Optional<Representations> representations = Optional.empty(); + @Builder.Default + private Optional<FormMetaData> metaData = Optional.empty(); } @Getter - @Builder + @Builder(toBuilder = true) public static class Representations { private String primaryFormDataRepresentation; private String primaryFormDataPdfRepresentation; diff --git a/common/src/main/java/de/ozgcloud/eingang/common/formdata/FormMetaData.java b/common/src/main/java/de/ozgcloud/eingang/common/formdata/FormMetaData.java new file mode 100644 index 0000000000000000000000000000000000000000..c84b8b634ee20fc695a27e194a6ed3bae0554621 --- /dev/null +++ b/common/src/main/java/de/ozgcloud/eingang/common/formdata/FormMetaData.java @@ -0,0 +1,19 @@ +package de.ozgcloud.eingang.common.formdata; + +import java.time.ZonedDateTime; + +public interface FormMetaData { + + ZonedDateTime getOrigin(); + ZonedDateTime getDelivery(); + + /** + * Returns the value of the Entry, or null if this MetaData contains no Entry + * for the name. + * + * @param name Name of the requested Entry + * @return Value of the Entry + */ + String getEntry(String name); + +} diff --git a/common/src/test/java/de/ozgcloud/eingang/common/formdata/FormDataControlTestFactory.java b/common/src/test/java/de/ozgcloud/eingang/common/formdata/FormDataControlTestFactory.java new file mode 100644 index 0000000000000000000000000000000000000000..e95c1e0fccf66519d23c26008a3a145bf562a2ff --- /dev/null +++ b/common/src/test/java/de/ozgcloud/eingang/common/formdata/FormDataControlTestFactory.java @@ -0,0 +1,23 @@ +package de.ozgcloud.eingang.common.formdata; + +import java.util.Optional; + +import de.ozgcloud.eingang.common.formdata.FormData.FormDataControl; +import de.ozgcloud.eingang.common.formdata.FormData.Representations; + +public class FormDataControlTestFactory { + + public static String PRIMARY_FORM_DATA_REPRESENTATION = "Antrag.xml"; + + public static FormDataControl create() { + return createBuilder().build(); + } + + public static FormDataControl.FormDataControlBuilder createBuilder() { + return FormDataControl.builder() + .representations(Optional.of(Representations.builder() + .primaryFormDataRepresentation(PRIMARY_FORM_DATA_REPRESENTATION) + .build())) + .metaData(Optional.of(FormMetaDataTestFactory.create())); + } +} diff --git a/common/src/test/java/de/ozgcloud/eingang/common/formdata/FormDataTestFactory.java b/common/src/test/java/de/ozgcloud/eingang/common/formdata/FormDataTestFactory.java index 05bdcffff581a6e8ce7e4f56fe5d86cb53054bb0..52dcddeaf62afa188e0716294bf84d615eb5c945 100644 --- a/common/src/test/java/de/ozgcloud/eingang/common/formdata/FormDataTestFactory.java +++ b/common/src/test/java/de/ozgcloud/eingang/common/formdata/FormDataTestFactory.java @@ -51,6 +51,8 @@ public class FormDataTestFactory { public static final String ATTACHMENT_GROUP_2 = "FileGroup2"; + public static final String VORGANG_ID = "vorgangId"; + public static FormData create() { return createBuilder().build(); } @@ -60,6 +62,7 @@ public class FormDataTestFactory { .header(FormHeaderTestFactory.create()) .antragsteller(AntragstellerTestFactory.create()) .zustaendigeStelle(ZustaendigeStelleTestFactory.create()) + .control(FormDataControlTestFactory.create()) .formData(Map.of( SIMPLE_VALUE_KEY, SIMPLE_VALUE, SUBFORM_KEY, SUBFORM_VALUE, diff --git a/common/src/test/java/de/ozgcloud/eingang/common/formdata/FormMetaDataTestFactory.java b/common/src/test/java/de/ozgcloud/eingang/common/formdata/FormMetaDataTestFactory.java new file mode 100644 index 0000000000000000000000000000000000000000..987fef7dde61f9d310b1700c9b927119a6af6105 --- /dev/null +++ b/common/src/test/java/de/ozgcloud/eingang/common/formdata/FormMetaDataTestFactory.java @@ -0,0 +1,36 @@ +package de.ozgcloud.eingang.common.formdata; + +import java.time.ZonedDateTime; + +public class FormMetaDataTestFactory { + + public static final String XTA_IDENTIFIER_ENTRY_NAME = "xtaIdentifier"; + + public static final String XTA_IDENTIFIER = "vbe:010550120100"; + public static final String OE_ID = "010550120100"; + + public static FormMetaData create() { + return new FormMetaData() { + + @Override + public ZonedDateTime getOrigin() { + return ZonedDateTime.now(); + } + + @Override + public ZonedDateTime getDelivery() { + return ZonedDateTime.now(); + } + + @Override + public String getEntry(String name) { + switch (name) { + case XTA_IDENTIFIER_ENTRY_NAME: + return XTA_IDENTIFIER; + } + return null; + } + + }; + } +} diff --git a/enterprise-adapter/pom.xml b/enterprise-adapter/pom.xml index 2b493a100ac22855b3428759f89b1748c29dadce..00e281f9f923419d7cf6863b94ce5a3fd627c25b 100644 --- a/enterprise-adapter/pom.xml +++ b/enterprise-adapter/pom.xml @@ -4,7 +4,7 @@ <parent> <groupId>de.ozgcloud.eingang</groupId> <artifactId>eingang-manager</artifactId> - <version>2.13.0-SNAPSHOT</version> + <version>2.15.0-SNAPSHOT</version> </parent> <artifactId>enterprise-adapter</artifactId> <name>EM - Enterprise Interface Adapter</name> @@ -87,10 +87,9 @@ <executions> <execution> <id>build-image</id> - <phase> - install</phase> + <phase>install</phase> <goals> - <goal>build-image</goal> + <goal>build-image-no-fork</goal> </goals> </execution> </executions> diff --git a/enterprise-adapter/src/test/java/de/ozgcloud/eingang/enterprise/entry/EnterpriseEntryITCase.java b/enterprise-adapter/src/test/java/de/ozgcloud/eingang/enterprise/entry/EnterpriseEntryITCase.java index 86d4309910b98191d19bfc9a33b8b97fed0f33c9..edde8e256ad108a7458f4325b7444c4a585f776d 100644 --- a/enterprise-adapter/src/test/java/de/ozgcloud/eingang/enterprise/entry/EnterpriseEntryITCase.java +++ b/enterprise-adapter/src/test/java/de/ozgcloud/eingang/enterprise/entry/EnterpriseEntryITCase.java @@ -64,6 +64,7 @@ class EnterpriseEntryITCase { assertThat(formData).isNotNull(); } + @Test void shouldHaveNoOfRepresentations() { var formData = doPostRequest(); diff --git a/fim-adapter/pom.xml b/fim-adapter/pom.xml index e7dde98a9f4d4cb33a1b755810a51be5287675d5..ea5d7e81c9b3605dfa58ed04af46467360b80100 100644 --- a/fim-adapter/pom.xml +++ b/fim-adapter/pom.xml @@ -4,7 +4,7 @@ <parent> <groupId>de.ozgcloud.eingang</groupId> <artifactId>eingang-manager</artifactId> - <version>2.13.0-SNAPSHOT</version> + <version>2.15.0-SNAPSHOT</version> </parent> <artifactId>fim-adapter</artifactId> <name>Eingangs Adapter - FIM</name> diff --git a/fim-adapter/src/main/java/de/ozgcloud/eingang/fim/AntragstellerExtractor.java b/fim-adapter/src/main/java/de/ozgcloud/eingang/fim/AntragstellerExtractor.java deleted file mode 100644 index 94a0b6821db48548ad8f82c65b06129e6262d0ab..0000000000000000000000000000000000000000 --- a/fim-adapter/src/main/java/de/ozgcloud/eingang/fim/AntragstellerExtractor.java +++ /dev/null @@ -1,27 +0,0 @@ -package de.ozgcloud.eingang.fim; - -import de.ozgcloud.eingang.common.formdata.Antragsteller; -import de.ozgcloud.eingang.common.formdata.FormData; - -import java.util.Map; - -public interface AntragstellerExtractor { - - default void extractAntragsteller(final FormData.FormDataBuilder builder, final FormData initialFormData) { - final FormData current = builder.build(); - final Map<String, Object> anzeigenErsteller = FimDataUtil.getSubmap(current.getFormData(), "G17002112"); - final Map<String, Object> anschrift = FimDataUtil.getSubmap(anzeigenErsteller, "G60000086"); - - Antragsteller antragsteller = Antragsteller.builder() - .vorname(FimDataUtil.getValue(anzeigenErsteller, "F60000228").orElse(null)) - .nachname(FimDataUtil.getValue(anzeigenErsteller, "F60000227").orElse(null)) - .email(FimDataUtil.getValue(anzeigenErsteller, "F60000242").orElse(null)) - .strasse(FimDataUtil.getValue(anschrift, "F60000243").orElse(null)) - .hausnummer(FimDataUtil.getValue(anschrift, "F60000244").orElse(null)) - .plz(FimDataUtil.getValue(anschrift, "F60000246").orElse(null)) - .ort(FimDataUtil.getValue(anschrift, "F60000247").orElse(null)) - - .build(); - builder.antragsteller(antragsteller); - } -} diff --git a/fim-adapter/src/main/java/de/ozgcloud/eingang/fim/FimBasedAdapter.java b/fim-adapter/src/main/java/de/ozgcloud/eingang/fim/FimBasedAdapter.java index 5849cf8e8f9e1f9ad90bb87fa28ef75ed75d71cd..6a6a8ce22f230439482be03567c495388c3a8915 100644 --- a/fim-adapter/src/main/java/de/ozgcloud/eingang/fim/FimBasedAdapter.java +++ b/fim-adapter/src/main/java/de/ozgcloud/eingang/fim/FimBasedAdapter.java @@ -1,74 +1,96 @@ package de.ozgcloud.eingang.fim; -import de.ozgcloud.eingang.common.formdata.FormData; -import de.ozgcloud.eingang.common.formdata.FormHeader; -import de.ozgcloud.eingang.common.formdata.IncomingFile; -import de.ozgcloud.eingang.semantik.enginebased.EngineBasedSemantikAdapter; -import lombok.extern.log4j.Log4j2; +import java.io.IOException; +import java.util.Collections; +import java.util.List; +import java.util.Optional; + +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.ParserConfigurationException; + import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import org.w3c.dom.Document; import org.xml.sax.SAXException; -import javax.xml.parsers.DocumentBuilder; -import javax.xml.parsers.DocumentBuilderFactory; -import javax.xml.parsers.ParserConfigurationException; -import java.io.IOException; -import java.util.Optional; +import de.ozgcloud.eingang.common.formdata.FormData; +import de.ozgcloud.eingang.common.formdata.FormData.FormDataControl; +import de.ozgcloud.eingang.common.formdata.FormData.Representations; +import de.ozgcloud.eingang.common.formdata.IncomingFile; +import de.ozgcloud.eingang.semantik.enginebased.EngineBasedSemantikAdapter; +import lombok.NonNull; +import lombok.extern.log4j.Log4j2; @Log4j2 @Component public class FimBasedAdapter implements EngineBasedSemantikAdapter { - static final String FIM_FORM_ENGINE_NAME = "FIM"; - - @Autowired - private FimService fimService; - - @Override - public boolean isResponsible(final FormData formData) { - final String formEngineName = formData.getHeader().getFormEngineName(); - return FIM_FORM_ENGINE_NAME.equals(formEngineName); - } - - @Override - public FormData parseFormData(final FormData initialFormData) { - LOG.info("FIM Mapper running to map formData"); - final Optional<String> entryPointOpt = getEntryPoint(initialFormData.getHeader()); - if (entryPointOpt.isEmpty()) { - LOG.error("No entry point found in metadata file for fim data mapping"); - return initialFormData; - } - final Optional<IncomingFile> fileOpt = findFile(initialFormData, entryPointOpt.get()); - if (fileOpt.isEmpty()) { - LOG.error("Entry point file not found for fim data mapping"); - return initialFormData; - } - try { - final Document document = loadDocument(fileOpt.get()); - return fimService.transformDocument(document, initialFormData); - } catch (ParserConfigurationException | SAXException | IOException | FimException e) { - LOG.error("Can't transform document into fim formdata"); - return initialFormData; - } - } - - private Optional<IncomingFile> findFile(final FormData formData, final String name) { - for (IncomingFile file : formData.getRepresentations()) { - if (file.getName().endsWith(name)) { - return Optional.of(file); - } - } - return Optional.empty(); - } - - private Optional<String> getEntryPoint(final FormHeader formHeader) { - // FIXME OZG-5778 sollte über formdata metadaten kommen statt aus dem meta file geparsed zu werden - return Optional.of("Antrag.xml"); - } - - private Document loadDocument(final IncomingFile incomingFile) throws ParserConfigurationException, IOException, SAXException { - final DocumentBuilder builder = DocumentBuilderFactory.newInstance().newDocumentBuilder(); - return builder.parse(incomingFile.getContentStream()); - } + static final String FIM_FORM_ENGINE_NAME = "FIM"; + + static final String DEFAULT_FORMDATA_REPRESENTATION_NAME = "Antrag.xml"; + + @Autowired + private FimService fimService; + + @Autowired(required = false) + private List<FimEngineBasedMapper> mappers = Collections.emptyList(); + + @Override + public boolean isResponsible(final FormData formData) { + final String formEngineName = formData.getHeader().getFormEngineName(); + return FIM_FORM_ENGINE_NAME.equals(formEngineName); + } + + @Override + public FormData parseFormData(final FormData initialFormData) { + var mapped = useMappers(initialFormData); + LOG.info("FIM Mapper running to map formData"); + + return findFile(initialFormData, getEntryPoint(initialFormData.getControl())) + .map(primaryRepresentation -> doParsing(mapped, primaryRepresentation)) + .orElseGet(() -> { + LOG.error("Entry point file not found for fim data mapping"); + return mapped; + }); + } + + private FormData useMappers(FormData inFormData) { + var processedFormData = inFormData; + + for (var mapper : mappers) { + processedFormData = mapper.parseFormData(processedFormData); + } + + return processedFormData; + } + + private Optional<IncomingFile> findFile(final FormData formData, final String name) { + return formData.getRepresentations().stream() + .filter(file -> file.getName().endsWith(name)) + .findFirst(); + } + + private FormData doParsing(@NonNull FormData formData, @NonNull IncomingFile formDataPrimaryRepresentation) { + try { + return fimService.transformDocument(loadDocument(formDataPrimaryRepresentation), formData); + } catch (ParserConfigurationException | SAXException | IOException | FimException e) { + LOG.error("Can't transform document into fim formdata.", e); + return formData; + } + } + + String getEntryPoint(FormDataControl formDataControl) { + return formDataControl.getRepresentations().map(Representations::getPrimaryFormDataRepresentation) + .orElseGet(() -> { + LOG.error("No entry point found in metadata file for fim data mapping. Trying default."); + return DEFAULT_FORMDATA_REPRESENTATION_NAME; + }); + } + + private Document loadDocument(final IncomingFile incomingFile) throws ParserConfigurationException, IOException, SAXException { + final DocumentBuilder builder = DocumentBuilderFactory.newInstance().newDocumentBuilder(); + return builder.parse(incomingFile.getContentStream()); + } + } diff --git a/fim-adapter/src/main/java/de/ozgcloud/eingang/fim/FimDataMapper.java b/fim-adapter/src/main/java/de/ozgcloud/eingang/fim/FimDataMapper.java index d7f0af4144888172fa1c9f6600efb7d95faf5b0c..84ea086db65f80050e41f253694a1c674f017285 100644 --- a/fim-adapter/src/main/java/de/ozgcloud/eingang/fim/FimDataMapper.java +++ b/fim-adapter/src/main/java/de/ozgcloud/eingang/fim/FimDataMapper.java @@ -1,9 +1,9 @@ package de.ozgcloud.eingang.fim; -import de.ozgcloud.eingang.common.formdata.FormData; -import de.ozgcloud.eingang.common.formdata.IncomingFile; -import de.ozgcloud.eingang.common.formdata.IncomingFileGroup; -import lombok.extern.log4j.Log4j2; +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.Optional; + import org.apache.commons.lang3.function.TriFunction; import org.springframework.stereotype.Service; import org.w3c.dom.Document; @@ -12,7 +12,8 @@ import org.w3c.dom.Node; import org.w3c.dom.NodeList; import org.w3c.dom.Text; -import java.util.*; +import de.ozgcloud.eingang.common.formdata.FormData; +import lombok.extern.log4j.Log4j2; @Service @Log4j2 diff --git a/fim-adapter/src/main/java/de/ozgcloud/eingang/fim/FimEngineBasedMapper.java b/fim-adapter/src/main/java/de/ozgcloud/eingang/fim/FimEngineBasedMapper.java new file mode 100644 index 0000000000000000000000000000000000000000..f01ac99cc7eebb80f297041f7edba27bf91b2c23 --- /dev/null +++ b/fim-adapter/src/main/java/de/ozgcloud/eingang/fim/FimEngineBasedMapper.java @@ -0,0 +1,7 @@ +package de.ozgcloud.eingang.fim; + +import de.ozgcloud.eingang.semantik.enginebased.EngineBasedMapper; + +public interface FimEngineBasedMapper extends EngineBasedMapper { + +} diff --git a/fim-adapter/src/main/java/de/ozgcloud/eingang/fim/FimSchemeAdapter.java b/fim-adapter/src/main/java/de/ozgcloud/eingang/fim/FimSchemeAdapter.java index 943d50fe215ddc943476628a18926e726af7db2e..95e74004a0062effcd03e05c58bb2638d3f5ad40 100644 --- a/fim-adapter/src/main/java/de/ozgcloud/eingang/fim/FimSchemeAdapter.java +++ b/fim-adapter/src/main/java/de/ozgcloud/eingang/fim/FimSchemeAdapter.java @@ -1,14 +1,15 @@ package de.ozgcloud.eingang.fim; -import lombok.extern.log4j.Log4j2; +import java.util.Map; +import java.util.Optional; + import org.w3c.dom.Element; import org.w3c.dom.NodeList; -import java.util.Map; -import java.util.Optional; +import lombok.extern.log4j.Log4j2; @Log4j2 -public abstract class FimSchemeAdapter implements ZustaendigeStelleExtractor, AntragstellerExtractor, VorgangsnameExtractor { +public abstract class FimSchemeAdapter { public abstract FimSchemeIdentifier forIdentifier(); diff --git a/fim-adapter/src/main/java/de/ozgcloud/eingang/fim/FimService.java b/fim-adapter/src/main/java/de/ozgcloud/eingang/fim/FimService.java index 5f3160fa21540964c2c9e049c07d2117590abd1f..381cb4e04896e27ae780605187fc041ebdd943e0 100644 --- a/fim-adapter/src/main/java/de/ozgcloud/eingang/fim/FimService.java +++ b/fim-adapter/src/main/java/de/ozgcloud/eingang/fim/FimService.java @@ -1,107 +1,139 @@ package de.ozgcloud.eingang.fim; -import de.ozgcloud.eingang.common.formdata.FormData; -import de.ozgcloud.eingang.common.formdata.FormHeader; -import io.micrometer.common.util.StringUtils; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Optional; + +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.ParserConfigurationException; + import jakarta.annotation.PostConstruct; -import lombok.extern.log4j.Log4j2; -import org.apache.logging.log4j.util.Strings; + import org.springframework.beans.factory.annotation.Autowired; import org.springframework.core.io.ResourceLoader; import org.springframework.stereotype.Service; import org.w3c.dom.Document; import org.xml.sax.SAXException; -import javax.xml.parsers.DocumentBuilder; -import javax.xml.parsers.DocumentBuilderFactory; -import javax.xml.parsers.ParserConfigurationException; -import java.io.IOException; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; -import java.util.Optional; +import de.ozgcloud.eingang.common.formdata.Antragsteller; +import de.ozgcloud.eingang.common.formdata.FormData; +import de.ozgcloud.eingang.common.formdata.FormHeader; +import io.micrometer.common.util.StringUtils; +import lombok.extern.log4j.Log4j2; @Service @Log4j2 public class FimService { - public static final String UNKNOWN_SCHEME_NAME = "unknown"; - - @Autowired - private FimProperties fimProperties; - - @Autowired - private FimDataMapper fimDataMapper; - - @Autowired - private ResourceLoader resourceLoader; - - @Autowired - private final List<FimSchemeAdapter> fimSchemeAdapters = new ArrayList<>(); - - private final FimSchemeCatalogue fimSchemeCatalogue = new FimSchemeCatalogue(); - private final FimSchemeAdapterCatalogue fimSchemeAdapterCatalogue = new FimSchemeAdapterCatalogue(); - - private static final FimSchemeAdapter DEFAULT_FIM_SCHEME_ADAPTER = new FimSchemeAdapter() { - @Override - public FimSchemeIdentifier forIdentifier() { return null; } - }; - - @PostConstruct - private void postConstruct() throws ParserConfigurationException, IOException, SAXException { - for (final FimSchemeAdapter fimSchemeAdapter : fimSchemeAdapters) { - fimSchemeAdapterCatalogue.put(fimSchemeAdapter.forIdentifier(), fimSchemeAdapter); - } - for (final String fimSchemaLocation : fimProperties.getSchemeLocations()) { - final FimScheme fimScheme = loadFimScheme(fimSchemaLocation.trim()); - fimSchemeCatalogue.put(fimScheme.getIdentifier(), fimScheme); - } - final FimScheme unknownScheme = buildUnknownScheme(); - fimSchemeCatalogue.put(unknownScheme.getIdentifier(), unknownScheme); - } - - private FimScheme loadFimScheme(final String path) throws ParserConfigurationException, IOException, SAXException { - LOG.debug("Load FIM schema: " + path); - final DocumentBuilder builder = DocumentBuilderFactory.newInstance().newDocumentBuilder(); - final Document doc = builder.parse(resourceLoader.getResource("classpath:" + path).getFile()); - final String targetNamespace = doc.getDocumentElement().getAttribute("targetNamespace"); - final FimSchemeIdentifier fimSchemeIdentifier = FimSchemeIdentifier.fromString(targetNamespace); - final FimSchemeAdapter fimSchemeAdapter = fimSchemeAdapterCatalogue.getOrDefault(fimSchemeIdentifier, DEFAULT_FIM_SCHEME_ADAPTER); - return new FimScheme(doc, fimSchemeIdentifier, fimSchemeAdapter); - } - - private FimScheme buildUnknownScheme() throws ParserConfigurationException { - final Document doc = DocumentBuilderFactory.newInstance().newDocumentBuilder().newDocument(); - final FimSchemeIdentifier unknownFimSchemeIdentifier = FimSchemeIdentifier.fromString(UNKNOWN_SCHEME_NAME); - final FimSchemeAdapter fimSchemeAdapter = fimSchemeAdapterCatalogue.get(unknownFimSchemeIdentifier); - return new FimScheme(doc, unknownFimSchemeIdentifier, fimSchemeAdapter); - } - - public FormData transformDocument(final Document document, final FormData initialFormData) { - final String[] tagParts = document.getDocumentElement().getTagName().split(":"); - final String namespacePrefix = tagParts.length < 2 ? "" : (":" + tagParts[0]); - final String schemeName = document.getDocumentElement().getAttribute("xmlns" + namespacePrefix); - if (StringUtils.isEmpty(schemeName)) { - throw new FimException("XML Document does not provide a scheme"); - } - final FimScheme scheme = getSchemeForIdentifier(schemeName); - final FormData.FormDataBuilder builder = fimDataMapper.apply(document, scheme, initialFormData); - - final FimSchemeAdapter adapter = scheme.getSchemeAdapter(); - - adapter.extractVorgangsname(builder, initialFormData); - adapter.extractAntragsteller(builder, initialFormData); - adapter.extractZustaendigeStelle(builder, initialFormData); - - return builder.build(); - } - - FimScheme getSchemeForIdentifier(final String fimSchemaName) { - final FimSchemeIdentifier fimSchemeIdentifier = FimSchemeIdentifier.fromString(fimSchemaName); - final FimScheme fimScheme = fimSchemeCatalogue.get(fimSchemeIdentifier); - if (fimScheme == null) { - LOG.error("Cannot find schema for: " + fimSchemaName); - return fimSchemeCatalogue.get(FimSchemeIdentifier.fromString(UNKNOWN_SCHEME_NAME)); - } - return fimScheme; - } -} + public static final String UNKNOWN_SCHEME_NAME = "unknown"; + + @Autowired + private FimProperties fimProperties; + + @Autowired + private FimDataMapper fimDataMapper; + + @Autowired + private ResourceLoader resourceLoader; + + @Autowired + private final List<FimSchemeAdapter> fimSchemeAdapters = new ArrayList<>(); + + private final FimSchemeCatalogue fimSchemeCatalogue = new FimSchemeCatalogue(); + private final FimSchemeAdapterCatalogue fimSchemeAdapterCatalogue = new FimSchemeAdapterCatalogue(); + + private static final FimSchemeAdapter DEFAULT_FIM_SCHEME_ADAPTER = new FimSchemeAdapter() { + @Override + public FimSchemeIdentifier forIdentifier() { + return null; + } + }; + + @PostConstruct + private void postConstruct() throws ParserConfigurationException, IOException, SAXException { + for (final FimSchemeAdapter fimSchemeAdapter : fimSchemeAdapters) { + fimSchemeAdapterCatalogue.put(fimSchemeAdapter.forIdentifier(), fimSchemeAdapter); + } + for (final String fimSchemaLocation : fimProperties.getSchemeLocations()) { + final FimScheme fimScheme = loadFimScheme(fimSchemaLocation.trim()); + fimSchemeCatalogue.put(fimScheme.getIdentifier(), fimScheme); + } + final FimScheme unknownScheme = buildUnknownScheme(); + fimSchemeCatalogue.put(unknownScheme.getIdentifier(), unknownScheme); + } + + private FimScheme loadFimScheme(final String path) throws ParserConfigurationException, IOException, SAXException { + LOG.debug("Load FIM schema: " + path); + final DocumentBuilder builder = DocumentBuilderFactory.newInstance().newDocumentBuilder(); + final Document doc = builder.parse(resourceLoader.getResource("classpath:" + path).getFile()); + final String targetNamespace = doc.getDocumentElement().getAttribute("targetNamespace"); + final FimSchemeIdentifier fimSchemeIdentifier = FimSchemeIdentifier.fromString(targetNamespace); + final FimSchemeAdapter fimSchemeAdapter = fimSchemeAdapterCatalogue.getOrDefault(fimSchemeIdentifier, DEFAULT_FIM_SCHEME_ADAPTER); + return new FimScheme(doc, fimSchemeIdentifier, fimSchemeAdapter); + } + + private FimScheme buildUnknownScheme() throws ParserConfigurationException { + final Document doc = DocumentBuilderFactory.newInstance().newDocumentBuilder().newDocument(); + final FimSchemeIdentifier unknownFimSchemeIdentifier = FimSchemeIdentifier.fromString(UNKNOWN_SCHEME_NAME); + final FimSchemeAdapter fimSchemeAdapter = fimSchemeAdapterCatalogue.get(unknownFimSchemeIdentifier); + return new FimScheme(doc, unknownFimSchemeIdentifier, fimSchemeAdapter); + } + + public FormData transformDocument(final Document document, final FormData initialFormData) { + final String[] tagParts = document.getDocumentElement().getTagName().split(":"); + final String namespacePrefix = tagParts.length < 2 ? "" : (":" + tagParts[0]); + final String schemeName = document.getDocumentElement().getAttribute("xmlns" + namespacePrefix); + if (StringUtils.isEmpty(schemeName)) { + throw new FimException("XML Document does not provide a scheme"); + } + final FimScheme scheme = getSchemeForIdentifier(schemeName); + final FormData.FormDataBuilder builder = fimDataMapper.apply(document, scheme, initialFormData); + + builder.header(initialFormData.getHeader()); + + extractAntragsteller(builder, initialFormData); + extractVorgangsname(builder, initialFormData); + + return builder.build(); + } + + FimScheme getSchemeForIdentifier(final String fimSchemaName) { + final FimSchemeIdentifier fimSchemeIdentifier = FimSchemeIdentifier.fromString(fimSchemaName); + final FimScheme fimScheme = fimSchemeCatalogue.get(fimSchemeIdentifier); + if (fimScheme == null) { + LOG.error("Cannot find schema for: " + fimSchemaName); + return fimSchemeCatalogue.get(FimSchemeIdentifier.fromString(UNKNOWN_SCHEME_NAME)); + } + return fimScheme; + } + + private void extractAntragsteller(final FormData.FormDataBuilder builder, final FormData initialFormData) { + final FormData current = builder.build(); + final Map<String, Object> anzeigenErsteller = FimDataUtil.getSubmap(current.getFormData(), "G17002112"); + final Map<String, Object> anschrift = FimDataUtil.getSubmap(anzeigenErsteller, "G60000086"); + + Antragsteller antragsteller = Antragsteller.builder() + .vorname(FimDataUtil.getValue(anzeigenErsteller, "F60000228").orElse(null)) + .nachname(FimDataUtil.getValue(anzeigenErsteller, "F60000227").orElse(null)) + .email(FimDataUtil.getValue(anzeigenErsteller, "F60000242").orElse(null)) + .strasse(FimDataUtil.getValue(anschrift, "F60000243").orElse(null)) + .hausnummer(FimDataUtil.getValue(anschrift, "F60000244").orElse(null)) + .plz(FimDataUtil.getValue(anschrift, "F60000246").orElse(null)) + .ort(FimDataUtil.getValue(anschrift, "F60000247").orElse(null)) + + .build(); + builder.antragsteller(antragsteller); + } + + private void extractVorgangsname(final FormData.FormDataBuilder builder, final FormData initialFormData) { + final FormData current = builder.build(); + final Optional<String> vorgangsname = FimDataUtil.getValue(current.getFormData(), "G17003529", "G05001479", "G05001480", "F05002753"); + + final FormHeader.FormHeaderBuilder headerBuilder = current.getHeader().toBuilder(); + + headerBuilder.formName(vorgangsname.orElse(null)); + builder.header(headerBuilder.build()); + } +} \ No newline at end of file diff --git a/fim-adapter/src/main/java/de/ozgcloud/eingang/fim/ZustaendigeStelleExtractor.java b/fim-adapter/src/main/java/de/ozgcloud/eingang/fim/ZustaendigeStelleExtractor.java deleted file mode 100644 index a77d159562ec8bf49d40025ff7b9c96bfc722b6b..0000000000000000000000000000000000000000 --- a/fim-adapter/src/main/java/de/ozgcloud/eingang/fim/ZustaendigeStelleExtractor.java +++ /dev/null @@ -1,7 +0,0 @@ -package de.ozgcloud.eingang.fim; - -import de.ozgcloud.eingang.common.formdata.FormData; - -public interface ZustaendigeStelleExtractor { - default void extractZustaendigeStelle (final FormData.FormDataBuilder builder, final FormData initialFormData) {} -} diff --git a/fim-adapter/src/main/java/de/ozgcloud/eingang/fim/ZustaendigeStelleMapper.java b/fim-adapter/src/main/java/de/ozgcloud/eingang/fim/ZustaendigeStelleMapper.java new file mode 100644 index 0000000000000000000000000000000000000000..72146cb778999343ef393a5d78365c1801893a0d --- /dev/null +++ b/fim-adapter/src/main/java/de/ozgcloud/eingang/fim/ZustaendigeStelleMapper.java @@ -0,0 +1,44 @@ +package de.ozgcloud.eingang.fim; + +import java.util.List; +import java.util.Objects; +import java.util.Optional; + +import org.springframework.stereotype.Component; + +import de.ozgcloud.eingang.common.formdata.FormData; +import de.ozgcloud.eingang.common.formdata.ZustaendigeStelle; +import lombok.NonNull; + +@Component +class ZustaendigeStelleMapper implements FimEngineBasedMapper { + + static final String XTA_IDENTIFIER_ENTRY_NAME = "xtaIdentifier"; + + // TODO OZG-7086 umstellen auf FIM Headerdaten + + @Override + public FormData parseFormData(FormData formData) { + return formData.getControl().getMetaData() + .map(metaData -> metaData.getEntry(XTA_IDENTIFIER_ENTRY_NAME)) + .filter(Objects::nonNull) + .map(oeId -> setOrganisationsEinheitId(formData.getZustaendigeStelles(), oeId)) + .map(zustStelle -> formData.toBuilder().zustaendigeStelle(zustStelle).build()) + .orElse(formData); + } + + private ZustaendigeStelle setOrganisationsEinheitId(List<ZustaendigeStelle> stelles, @NonNull String oeid) { + var builder = stelles.isEmpty() ? ZustaendigeStelle.builder() : stelles.getFirst().toBuilder(); + + extractOrganisationsEinheitId(oeid).ifPresent(builder::organisationseinheitenId); + return builder.build(); + } + + Optional<String> extractOrganisationsEinheitId(@NonNull String xtaIdentifier) { + var idx = xtaIdentifier.indexOf(":"); + if (idx < 0) { + return Optional.empty(); + } + return Optional.of(xtaIdentifier.substring(idx + 1)); + } +} diff --git a/fim-adapter/src/test/java/de/ozgcloud/eingang/fim/FimBasedAdapterTest.java b/fim-adapter/src/test/java/de/ozgcloud/eingang/fim/FimBasedAdapterTest.java new file mode 100644 index 0000000000000000000000000000000000000000..1a09b6a2ef3428543a3981d71f8aa8d38aaf5235 --- /dev/null +++ b/fim-adapter/src/test/java/de/ozgcloud/eingang/fim/FimBasedAdapterTest.java @@ -0,0 +1,46 @@ +package de.ozgcloud.eingang.fim; + +import static org.assertj.core.api.Assertions.*; + +import java.util.Optional; + +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; +import org.mockito.InjectMocks; + +import de.ozgcloud.eingang.common.formdata.FormData.Representations; +import de.ozgcloud.eingang.common.formdata.FormDataControlTestFactory; + +class FimBasedAdapterTest { + + @InjectMocks + private FimBasedAdapter adapter; + + @Nested + class TestGetEntryPoint { + + @Test + void shouldReturnPrimaryRepresentation() { + var result = adapter.getEntryPoint(FormDataControlTestFactory.create()); + + assertThat(result).isEqualTo(FormDataControlTestFactory.PRIMARY_FORM_DATA_REPRESENTATION); + } + + @Test + void shouldReturnDefaultOnMissingRepresentations() { + var result = adapter.getEntryPoint(FormDataControlTestFactory.createBuilder().representations(Optional.empty()).build()); + + assertThat(result).isEqualTo(FimBasedAdapter.DEFAULT_FORMDATA_REPRESENTATION_NAME); + } + + @Test + void shouldReturnDefaultOnMissingPrimary() { + var control = FormDataControlTestFactory.createBuilder().representations(Optional.of(Representations.builder().build())).build(); + + var result = adapter.getEntryPoint(control); + + assertThat(result).isEqualTo(FimBasedAdapter.DEFAULT_FORMDATA_REPRESENTATION_NAME); + } + } + +} diff --git a/fim-adapter/src/test/java/de/ozgcloud/eingang/fim/FimServiceITCase.java b/fim-adapter/src/test/java/de/ozgcloud/eingang/fim/FimServiceITCase.java index 970e470d8fae2a989611b2f51545667827ca9d3d..38075e210282b91976041e1365b61603eadc2a3d 100644 --- a/fim-adapter/src/test/java/de/ozgcloud/eingang/fim/FimServiceITCase.java +++ b/fim-adapter/src/test/java/de/ozgcloud/eingang/fim/FimServiceITCase.java @@ -1,241 +1,231 @@ package de.ozgcloud.eingang.fim; -import de.ozgcloud.common.test.ITCase; -import de.ozgcloud.eingang.common.formdata.FormData; -import de.ozgcloud.eingang.common.formdata.FormHeader; -import de.ozgcloud.eingang.common.formdata.IncomingFile; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.autoconfigure.ImportAutoConfiguration; - -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.test.context.ActiveProfiles; - -import org.w3c.dom.Document; -import org.xml.sax.SAXException; +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.AssertionsForClassTypes.assertThatThrownBy; -import javax.xml.parsers.DocumentBuilder; -import javax.xml.parsers.DocumentBuilderFactory; -import javax.xml.parsers.ParserConfigurationException; import java.io.File; import java.io.IOException; import java.util.List; import java.util.Map; + +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.ParserConfigurationException; + import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.autoconfigure.ImportAutoConfiguration; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.ActiveProfiles; +import org.w3c.dom.Document; +import org.xml.sax.SAXException; -import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.AssertionsForClassTypes.assertThatThrownBy; +import de.ozgcloud.common.test.ITCase; +import de.ozgcloud.eingang.common.formdata.FormData; +import de.ozgcloud.eingang.common.formdata.FormHeader; +import de.ozgcloud.eingang.common.formdata.IncomingFile; @ITCase @ActiveProfiles({ "itcase", "test" }) @ImportAutoConfiguration -@SpringBootTest(classes= FimTestConfig.class) +@SpringBootTest(classes = FimTestConfig.class) public class FimServiceITCase { - @Autowired - private FimService fimService; - - @Autowired - private FimBasedAdapter fimBasedAdapter; - - @Test - void shouldFailOnEmptyScheme() { - assertThatThrownBy(() -> { - final Document document = loadDocument("src/test/resources/test1.xml"); - fimService.transformDocument(document, FormData.builder().build()); - }).isInstanceOf(FimException.class).hasMessage("XML Document does not provide a scheme"); - } - - @Test - void shouldNoFindInvalidScheme() { - final FimScheme scheme = fimService.getSchemeForIdentifier("test"); - - assertThat(FimSchemeIdentifier.fromString("unknown")).isEqualTo(scheme.getIdentifier()); - } - - @Test - void shouldFindVersammlungsScheme() { - final FimScheme scheme = fimService.getSchemeForIdentifier("urn:xoev-de:xfall:standard:fim-s17000652_1.4"); - assertThat(scheme).isNotNull(); - } - - @Test - void shouldFindTest2Scheme() { - final FimScheme scheme = fimService.getSchemeForIdentifier("test2"); - assertThat(scheme).isNotNull(); - } - - @Test - void shouldTransformSimpleDocument() throws ParserConfigurationException, IOException, SAXException { - final Document document = loadDocument("src/test/resources/test2.xml"); - final FormData formData = fimService.transformDocument(document, FormData.builder().build()); - - final Map<String, Object> expected = Map.of( - "fim.S1235", Map.of("label", "Testkey", "value", "Testvalue"), - "fim.S1236", Map.of("label", "fim.S1236", "value", "Testvalue 2") - ); - assertThat(expected).isEqualTo(formData.getFormData()); - } - - @Test - void shouldTransformSimpleDocumentWithoutNamespace() throws ParserConfigurationException, IOException, SAXException { - final Document document = loadDocument("src/test/resources/test3.xml"); - final FormData formData = fimService.transformDocument(document, FormData.builder().build()); - - final Map<String, Object> expected = Map.of( - "fim.S1235", Map.of("label", "Testkey", "value", "Testvalue"), - "fim.S1236", Map.of("label", "fim.S1236", "value", "Testvalue 2") - ); - assertThat(expected).isEqualTo(formData.getFormData()); - } - - @Test - void shouldTransformDocument() throws ParserConfigurationException, IOException, SAXException { - final Document document = loadDocument("src/test/resources/S17000652V1.4_test01.xml"); - FormData formData = fimService.transformDocument(document, FormData.builder().build()); - - assertThat(formData).isNotNull(); - - final Map<String, Object> expected = Map.of( - "G17003529", Map.of( - "label","EfA|SH Standard", - "value", Map.of( - "G05001479", Map.of( - "label","nachrichtenkopf", - "value", Map.of( - "G05001480", Map.of( - "label","identifikation.nachricht", - "value", Map.of( - "F05002750", Map.of("label", "nachrichtenUUID", "value", "d447e43a-5723-4821-a170-cb44d2dbf143"), - "F05002751", Map.of("label", "erstellungszeitpunkt", "value", "2022-08-15T09:30:47"), - "F05002752", Map.of("label", "nachrichtentyp", "value", "fim.S17000652.17000652001004"), - "F05002753", Map.of("label", "dienstname", "value", "urn:fim:Versammlungsanzeige:1.4") - ) - ), - "G05001481", Map.of( - "label","Leser", - "value", Map.of( - "F05002754", Map.of("label", "Organisationsname", "value", "Celle"), - "F05002755", Map.of("label", "Organisationsschlüssel", "value", "vbe:010550120100"), - "F05002756", Map.of("label", "Kategorie", "value", "Versammlungsbehörde") - ) - ), - "G05001482", Map.of( - "label","Autor", - "value", Map.of( - "F05002754", Map.of("label", "Organisationsname", "value", "OSI-Onlinedienst Niedersachsen Versammlungsanzeige"), - "F05002755", Map.of("label", "Organisationsschlüssel", "value", "vbe:010550120100"), - "F05002756", Map.of("label", "Kategorie", "value", "Engagement- und Hobbyportal") - ) - ) - ) - ), - "F17005454", Map.of("label", "Datenschutzhinweis DSGVO", "value", "true"), - "F17005455", Map.of("label", "Zustimmung zu einem digitalen Bescheid", "value", "true"), - "F17005533", Map.of("label", "UUID", "value", "String") - ) - ), - "F17009191", Map.of("label", "Anzeige durch Person", "value", "true"), - "F17003371", Map.of("label", "Anzeigenart", "value", "String") - ); - - assertThat(expected).isEqualTo(formData.getFormData()); - } - - @Test - void shouldHaveNameInHeader() throws ParserConfigurationException, IOException, SAXException { - final Document document = loadDocument("src/test/resources/antrag.xml"); - FormData formData = fimService.transformDocument(document, FormData.builder().build()); - - assertThat(formData).isNotNull(); - - assertThat(formData.getHeader().getFormName()).isEqualTo("urn:fim:Versammlungsanzeige:1.4"); - } - - @Test - void shouldHaveAntragsteller() throws ParserConfigurationException, IOException, SAXException { - final Document document = loadDocument("src/test/resources/antrag.xml"); - FormData formData = fimService.transformDocument(document, FormData.builder().build()); - - assertThat(formData).isNotNull(); - - assertThat(formData.getAntragsteller()).isNotNull(); - } - - @Test - void shouldHaveAntragstellerAntragstellerData() throws ParserConfigurationException, IOException, SAXException { - final Document document = loadDocument("src/test/resources/antrag.xml"); - FormData formData = fimService.transformDocument(document, FormData.builder().build()); - - assertThat(formData).isNotNull(); - - assertThat(formData.getAntragsteller().getVorname()).isEqualTo("Jörg"); - assertThat(formData.getAntragsteller().getNachname()).isEqualTo("Bolay"); - assertThat(formData.getAntragsteller().getStrasse()).isEqualTo("Muster"); - assertThat(formData.getAntragsteller().getHausnummer()).isEqualTo("1"); - assertThat(formData.getAntragsteller().getPlz()).isEqualTo("12345"); - assertThat(formData.getAntragsteller().getOrt()).isEqualTo("Muster"); - } - - @Test - void shouldFallbackUnknownScheme() { - IncomingFile r1 = IncomingFile.builder().name("src/test/resources/test3/Antrag.xml").file(new File("src/test/resources/test3/Antrag.xml")).build(); - IncomingFile r2 = IncomingFile.builder().name("src/test/resources/test3/fim_xtaMetadata.xml").build(); - final FormData initialFormData = FormData.builder() - .header(FormHeader.builder().channel("XTA").formEngineName("FIM").build()) - .representations(List.of(r1, r2)).build(); - - FormData formData = fimBasedAdapter.parseFormData(initialFormData); - - assertThat(formData).isNotNull(); - - final Map<String, Object> expected = Map.of( - "G17003529", Map.of( - "label","G17003529", - "value", Map.of( - "G05001479", Map.of( - "label","G05001479", - "value", Map.of( - "G05001480", Map.of( - "label","G05001480", - "value", Map.of( - "F05002750", Map.of("label", "F05002750", "value", "d447e43a-5723-4821-a170-cb44d2dbf143"), - "F05002751", Map.of("label", "F05002751", "value", "2022-08-15T09:30:47"), - "F05002752", Map.of("label", "F05002752", "value", "fim.S17000652.17000652001004"), - "F05002753", Map.of("label", "F05002753", "value", "urn:fim:Versammlungsanzeige:1.4") - ) - ), - "G05001481", Map.of( - "label","G05001481", - "value", Map.of( - "F05002754", Map.of("label", "F05002754", "value", "Celle"), - "F05002755", Map.of("label", "F05002755", "value", "vbe:010550120100"), - "F05002756", Map.of("label", "F05002756", "value", "Versammlungsbehörde") - ) - ), - "G05001482", Map.of( - "label","G05001482", - "value", Map.of( - "F05002754", Map.of("label", "F05002754", "value", "OSI-Onlinedienst Niedersachsen Versammlungsanzeige"), - "F05002755", Map.of("label", "F05002755", "value", "vbe:010550120100"), - "F05002756", Map.of("label", "F05002756", "value", "Engagement- und Hobbyportal") - ) - ) - ) - ), - "F17005454", Map.of("label", "F17005454", "value", "true"), - "F17005455", Map.of("label", "F17005455", "value", "true"), - "F17005533", Map.of("label", "F17005533", "value", "String") - ) - ), - "F17009191", Map.of("label", "F17009191", "value", "true"), - "F17003371", Map.of("label", "F17003371", "value", "String") - ); - - assertThat(expected).isEqualTo(formData.getFormData()); - } - - private Document loadDocument(final String path) throws ParserConfigurationException, IOException, SAXException { - final DocumentBuilder builder = DocumentBuilderFactory.newInstance().newDocumentBuilder(); - return builder.parse(new File(path)); - } + @Autowired + private FimService fimService; + + @Autowired + private FimBasedAdapter fimBasedAdapter; + + @Test + void shouldFailOnEmptyScheme() { + assertThatThrownBy(() -> { + final Document document = loadDocument("src/test/resources/test1.xml"); + fimService.transformDocument(document, FormData.builder().build()); + }).isInstanceOf(FimException.class).hasMessage("XML Document does not provide a scheme"); + } + + @Test + void shouldNoFindInvalidScheme() { + final FimScheme scheme = fimService.getSchemeForIdentifier("test"); + + assertThat(FimSchemeIdentifier.fromString("unknown")).isEqualTo(scheme.getIdentifier()); + } + + @Test + void shouldFindVersammlungsScheme() { + final FimScheme scheme = fimService.getSchemeForIdentifier("urn:xoev-de:xfall:standard:fim-s17000652_1.4"); + assertThat(scheme).isNotNull(); + } + + @Test + void shouldFindTest2Scheme() { + final FimScheme scheme = fimService.getSchemeForIdentifier("test2"); + assertThat(scheme).isNotNull(); + } + + @Test + void shouldTransformSimpleDocument() throws ParserConfigurationException, IOException, SAXException { + final Document document = loadDocument("src/test/resources/test2.xml"); + final FormData formData = fimService.transformDocument(document, FormData.builder().build()); + + final Map<String, Object> expected = Map.of( + "fim.S1235", Map.of("label", "Testkey", "value", "Testvalue"), + "fim.S1236", Map.of("label", "fim.S1236", "value", "Testvalue 2")); + assertThat(expected).isEqualTo(formData.getFormData()); + } + + @Test + void shouldTransformSimpleDocumentWithoutNamespace() throws ParserConfigurationException, IOException, SAXException { + final Document document = loadDocument("src/test/resources/test3.xml"); + final FormData formData = fimService.transformDocument(document, FormData.builder().build()); + + final Map<String, Object> expected = Map.of( + "fim.S1235", Map.of("label", "Testkey", "value", "Testvalue"), + "fim.S1236", Map.of("label", "fim.S1236", "value", "Testvalue 2")); + assertThat(expected).isEqualTo(formData.getFormData()); + } + + @Test + void shouldTransformDocument() throws ParserConfigurationException, IOException, SAXException { + final Document document = loadDocument("src/test/resources/S17000652V1.4_test01.xml"); + FormData formData = fimService.transformDocument(document, FormData.builder().build()); + + assertThat(formData).isNotNull(); + + final Map<String, Object> expected = Map.of( + "G17003529", Map.of( + "label", "EfA|SH Standard", + "value", Map.of( + "G05001479", Map.of( + "label", "nachrichtenkopf", + "value", Map.of( + "G05001480", Map.of( + "label", "identifikation.nachricht", + "value", Map.of( + "F05002750", + Map.of("label", "nachrichtenUUID", "value", "d447e43a-5723-4821-a170-cb44d2dbf143"), + "F05002751", + Map.of("label", "erstellungszeitpunkt", "value", "2022-08-15T09:30:47"), + "F05002752", + Map.of("label", "nachrichtentyp", "value", "fim.S17000652.17000652001004"), + "F05002753", + Map.of("label", "dienstname", "value", "urn:fim:Versammlungsanzeige:1.4"))), + "G05001481", Map.of( + "label", "Leser", + "value", Map.of( + "F05002754", Map.of("label", "Organisationsname", "value", "Celle"), + "F05002755", + Map.of("label", "Organisationsschlüssel", "value", "vbe:010550120100"), + "F05002756", Map.of("label", "Kategorie", "value", "Versammlungsbehörde"))), + "G05001482", Map.of( + "label", "Autor", + "value", Map.of( + "F05002754", + Map.of("label", "Organisationsname", "value", + "OSI-Onlinedienst Niedersachsen Versammlungsanzeige"), + "F05002755", + Map.of("label", "Organisationsschlüssel", "value", "vbe:010550120100"), + "F05002756", + Map.of("label", "Kategorie", "value", "Engagement- und Hobbyportal"))))), + "F17005454", Map.of("label", "Datenschutzhinweis DSGVO", "value", "true"), + "F17005455", Map.of("label", "Zustimmung zu einem digitalen Bescheid", "value", "true"), + "F17005533", Map.of("label", "UUID", "value", "String"))), + "F17009191", Map.of("label", "Anzeige durch Person", "value", "true"), + "F17003371", Map.of("label", "Anzeigenart", "value", "String")); + + assertThat(expected).isEqualTo(formData.getFormData()); + } + + @Test + void shouldHaveNameInHeader() throws ParserConfigurationException, IOException, SAXException { + final Document document = loadDocument("src/test/resources/antrag.xml"); + FormData formData = fimService.transformDocument(document, FormData.builder().build()); + + assertThat(formData).isNotNull(); + + assertThat(formData.getHeader().getFormName()).isEqualTo("urn:fim:Versammlungsanzeige:1.4"); + } + + @Test + void shouldHaveAntragsteller() throws ParserConfigurationException, IOException, SAXException { + final Document document = loadDocument("src/test/resources/antrag.xml"); + FormData formData = fimService.transformDocument(document, FormData.builder().build()); + + assertThat(formData).isNotNull(); + + assertThat(formData.getAntragsteller()).isNotNull(); + } + + @Test + void shouldHaveAntragstellerAntragstellerData() throws ParserConfigurationException, IOException, SAXException { + final Document document = loadDocument("src/test/resources/antrag.xml"); + FormData formData = fimService.transformDocument(document, FormData.builder().build()); + + assertThat(formData).isNotNull(); + + assertThat(formData.getAntragsteller().getVorname()).isEqualTo("Jörg"); + assertThat(formData.getAntragsteller().getNachname()).isEqualTo("Bolay"); + assertThat(formData.getAntragsteller().getStrasse()).isEqualTo("Muster"); + assertThat(formData.getAntragsteller().getHausnummer()).isEqualTo("1"); + assertThat(formData.getAntragsteller().getPlz()).isEqualTo("12345"); + assertThat(formData.getAntragsteller().getOrt()).isEqualTo("Muster"); + } + + @Test + void shouldFallbackUnknownScheme() { + IncomingFile r1 = IncomingFile.builder().name("src/test/resources/test3/Antrag.xml").file(new File("src/test/resources/test3/Antrag.xml")) + .build(); + IncomingFile r2 = IncomingFile.builder().name("src/test/resources/test3/fim_xtaMetadata.xml").build(); + final FormData initialFormData = FormData.builder() + .header(FormHeader.builder().channel("XTA").formEngineName("FIM").build()) + .representations(List.of(r1, r2)).build(); + + FormData formData = fimBasedAdapter.parseFormData(initialFormData); + + assertThat(formData).isNotNull(); + + final Map<String, Object> expected = Map.of( + "G17003529", Map.of( + "label", "G17003529", + "value", Map.of( + "G05001479", Map.of( + "label", "G05001479", + "value", Map.of( + "G05001480", Map.of( + "label", "G05001480", + "value", Map.of( + "F05002750", + Map.of("label", "F05002750", "value", "d447e43a-5723-4821-a170-cb44d2dbf143"), + "F05002751", Map.of("label", "F05002751", "value", "2022-08-15T09:30:47"), + "F05002752", Map.of("label", "F05002752", "value", "fim.S17000652.17000652001004"), + "F05002753", + Map.of("label", "F05002753", "value", "urn:fim:Versammlungsanzeige:1.4"))), + "G05001481", Map.of( + "label", "G05001481", + "value", Map.of( + "F05002754", Map.of("label", "F05002754", "value", "Celle"), + "F05002755", Map.of("label", "F05002755", "value", "vbe:010550120100"), + "F05002756", Map.of("label", "F05002756", "value", "Versammlungsbehörde"))), + "G05001482", Map.of( + "label", "G05001482", + "value", Map.of( + "F05002754", + Map.of("label", "F05002754", "value", + "OSI-Onlinedienst Niedersachsen Versammlungsanzeige"), + "F05002755", Map.of("label", "F05002755", "value", "vbe:010550120100"), + "F05002756", Map.of("label", "F05002756", "value", "Engagement- und Hobbyportal"))))), + "F17005454", Map.of("label", "F17005454", "value", "true"), + "F17005455", Map.of("label", "F17005455", "value", "true"), + "F17005533", Map.of("label", "F17005533", "value", "String"))), + "F17009191", Map.of("label", "F17009191", "value", "true"), + "F17003371", Map.of("label", "F17003371", "value", "String")); + + assertThat(expected).isEqualTo(formData.getFormData()); + } + + private Document loadDocument(final String path) throws ParserConfigurationException, IOException, SAXException { + final DocumentBuilder builder = DocumentBuilderFactory.newInstance().newDocumentBuilder(); + return builder.parse(new File(path)); + } } diff --git a/fim-adapter/src/test/java/de/ozgcloud/eingang/fim/FimTestConfig.java b/fim-adapter/src/test/java/de/ozgcloud/eingang/fim/FimTestConfig.java index f0a28ec4b7be509a0de6663720ab2f2964546065..8e88e6f0ae161bffefca00daaef61bb3871a508a 100644 --- a/fim-adapter/src/test/java/de/ozgcloud/eingang/fim/FimTestConfig.java +++ b/fim-adapter/src/test/java/de/ozgcloud/eingang/fim/FimTestConfig.java @@ -6,6 +6,6 @@ import org.springframework.context.annotation.Configuration; @Configuration @EnableAutoConfiguration -@ComponentScan("de.ozgcloud.eingang.fim") +@ComponentScan("de.ozgcloud.eingang") public class FimTestConfig { } diff --git a/fim-adapter/src/test/java/de/ozgcloud/eingang/fim/ZustaendigeStelleMapperTest.java b/fim-adapter/src/test/java/de/ozgcloud/eingang/fim/ZustaendigeStelleMapperTest.java new file mode 100644 index 0000000000000000000000000000000000000000..23fa26757fccee0f45863f256e9f34522ccae81c --- /dev/null +++ b/fim-adapter/src/test/java/de/ozgcloud/eingang/fim/ZustaendigeStelleMapperTest.java @@ -0,0 +1,44 @@ +package de.ozgcloud.eingang.fim; + +import static org.assertj.core.api.Assertions.*; + +import org.junit.jupiter.api.Test; +import org.mockito.InjectMocks; + +import de.ozgcloud.eingang.common.formdata.FormDataTestFactory; +import de.ozgcloud.eingang.common.formdata.FormMetaDataTestFactory; +import de.ozgcloud.eingang.common.formdata.ZustaendigeStelle; + +class ZustaendigeStelleMapperTest { + + @InjectMocks + private ZustaendigeStelleMapper mapper; + + @Test + void shouldSetOrganisationsEinheitId() { + var parsed = mapper.parseFormData(FormDataTestFactory.createBuilder().clearZustaendigeStelles().build()); + + assertThat(parsed.getZustaendigeStelles()).hasSize(1).first().extracting(ZustaendigeStelle::getOrganisationseinheitenId) + .isEqualTo(FormMetaDataTestFactory.OE_ID); + +// assertThat(parsed.getZustaendigeStelle().getOrganisationseinheitenId()).isEqualTo(FormMetaDataTestFactory.OE_ID); + } + + @Test + void shouldWorkWithoutGivenZustaendigeStelle() { + var parsed = mapper.parseFormData(FormDataTestFactory.createBuilder().clearZustaendigeStelles().build()); + + assertThat(parsed.getZustaendigeStelles()).hasSize(1).first().extracting(ZustaendigeStelle::getOrganisationseinheitenId) + .isNotNull(); + +// assertThat(parsed.getZustaendigeStelle()).isNotNull(); + } + + @Test + void shouldIgnoreMalformedDestinationId() { + var oeid = mapper.extractOrganisationsEinheitId("quatsch"); + + assertThat(oeid).isEmpty(); + } + +} diff --git a/formcycle-adapter/formcycle-adapter-impl/pom.xml b/formcycle-adapter/formcycle-adapter-impl/pom.xml index 4f85d9512aabbbe2a758a5893be9762303ff656e..3d5699205b4bcd63f2c78fe66dfbbda3fe5be060 100644 --- a/formcycle-adapter/formcycle-adapter-impl/pom.xml +++ b/formcycle-adapter/formcycle-adapter-impl/pom.xml @@ -29,7 +29,7 @@ <parent> <groupId>de.ozgcloud.eingang</groupId> <artifactId>formcycle-adapter</artifactId> - <version>2.13.0-SNAPSHOT</version> + <version>2.15.0-SNAPSHOT</version> <relativePath>../</relativePath> </parent> @@ -123,7 +123,7 @@ <id>build-image</id> <phase>install</phase> <goals> - <goal>build-image</goal> + <goal>build-image-no-fork</goal> </goals> </execution> </executions> diff --git a/formcycle-adapter/formcycle-adapter-impl/src/main/java/de/ozgcloud/eingang/formcycle/FormCycleServiceKontoMapper.java b/formcycle-adapter/formcycle-adapter-impl/src/main/java/de/ozgcloud/eingang/formcycle/FormCycleServiceKontoMapper.java index 3aceb97490468096ade62e9803525e90f0cf8a03..5185c70c92b3dff61db99fa0458be3019195a840 100644 --- a/formcycle-adapter/formcycle-adapter-impl/src/main/java/de/ozgcloud/eingang/formcycle/FormCycleServiceKontoMapper.java +++ b/formcycle-adapter/formcycle-adapter-impl/src/main/java/de/ozgcloud/eingang/formcycle/FormCycleServiceKontoMapper.java @@ -12,11 +12,13 @@ import org.mapstruct.ReportingPolicy; import de.ozgcloud.eingang.common.formdata.ServiceKonto; import de.ozgcloud.eingang.common.formdata.ServiceKonto.PostfachAddress; import de.ozgcloud.eingang.common.formdata.StringBasedIdentifier; +import de.ozgcloud.eingang.semantik.common.ServiceKontoFactory; @Mapper(collectionMappingStrategy = CollectionMappingStrategy.ADDER_PREFERRED, unmappedTargetPolicy = ReportingPolicy.WARN) interface FormCycleServiceKontoMapper { @Mapping(target = "postfachAddress", ignore = true) + @Mapping(target = "type", constant = ServiceKontoFactory.POSTFACH_TYPE_BAYERN_ID) @Mapping(target = "postfachAddresses", expression = "java(fromGrpcPostfachAddresses(serviceKonto))") ServiceKonto fromGrpc(FormCycleServiceKonto serviceKonto); diff --git a/formcycle-adapter/formcycle-adapter-impl/src/test/java/de/ozgcloud/eingang/formcycle/FormCycleFormDataMapperTest.java b/formcycle-adapter/formcycle-adapter-impl/src/test/java/de/ozgcloud/eingang/formcycle/FormCycleFormDataMapperTest.java index feb214cccd2dca6533c39109f6f85619be567304..077a22039a5d9da064404d03e2ec4c24b6584915 100644 --- a/formcycle-adapter/formcycle-adapter-impl/src/test/java/de/ozgcloud/eingang/formcycle/FormCycleFormDataMapperTest.java +++ b/formcycle-adapter/formcycle-adapter-impl/src/test/java/de/ozgcloud/eingang/formcycle/FormCycleFormDataMapperTest.java @@ -32,6 +32,7 @@ import org.mockito.InjectMocks; import org.mockito.Spy; import de.ozgcloud.eingang.common.formdata.FormHeaderTestFactory; +import de.ozgcloud.eingang.common.formdata.ZustaendigeStelle; import de.ozgcloud.vorgang.common.grpc.GrpcFormDataMapper; class FormCycleFormDataMapperTest { @@ -59,7 +60,9 @@ class FormCycleFormDataMapperTest { void shouldMapZustaendigeStelle() { var mapped = mapper.toFormData(FormCycleFormDataTestFactory.create()); - assertThat(mapped.getZustaendigeStelle().getOrganisationseinheitenId()).isEqualTo(FormCycleFormHeaderTestFactory.ORGANISATIONSEINHEIT_ID); + assertThat(mapped.getZustaendigeStelles()) + .extracting(ZustaendigeStelle::getOrganisationseinheitenId) + .containsExactly(FormCycleFormHeaderTestFactory.ORGANISATIONSEINHEIT_ID); } } diff --git a/formcycle-adapter/formcycle-adapter-impl/src/test/java/de/ozgcloud/eingang/formcycle/FormCycleServiceKontoMapperTest.java b/formcycle-adapter/formcycle-adapter-impl/src/test/java/de/ozgcloud/eingang/formcycle/FormCycleServiceKontoMapperTest.java index b328284eb6b3ab4fdf010dd4240d4726ebd13209..562bd419be832ff41a59fd1eb2215ed32961d2bd 100644 --- a/formcycle-adapter/formcycle-adapter-impl/src/test/java/de/ozgcloud/eingang/formcycle/FormCycleServiceKontoMapperTest.java +++ b/formcycle-adapter/formcycle-adapter-impl/src/test/java/de/ozgcloud/eingang/formcycle/FormCycleServiceKontoMapperTest.java @@ -11,6 +11,7 @@ import org.mapstruct.factory.Mappers; import de.ozgcloud.eingang.common.formdata.ServiceKonto.PostfachAddress; import de.ozgcloud.eingang.common.formdata.ServiceKontoTestFactory; import de.ozgcloud.eingang.common.formdata.StringBasedIdentifier; +import de.ozgcloud.eingang.semantik.common.ServiceKontoFactory; class FormCycleServiceKontoMapperTest { @@ -20,6 +21,13 @@ class FormCycleServiceKontoMapperTest { @Nested class TestFromGrpcServiceKonto { + @Test + void shouldMapType() { + var result = mapper.fromGrpc(FormCycleServiceKontoTestFactory.create()); + + assertThat(result.getType()).isEqualTo(ServiceKontoFactory.POSTFACH_TYPE_BAYERN_ID); + } + @DisplayName("trustLevel") @Nested class TestTrustLevel { diff --git a/formcycle-adapter/formcycle-adapter-interface/pom.xml b/formcycle-adapter/formcycle-adapter-interface/pom.xml index d396e859955e6fe0fc0bead6994fb69e852e668f..917fad48d21b8e902c5ae8ba18941556cf984731 100644 --- a/formcycle-adapter/formcycle-adapter-interface/pom.xml +++ b/formcycle-adapter/formcycle-adapter-interface/pom.xml @@ -36,7 +36,7 @@ <groupId>de.ozgcloud.eingang</groupId> <artifactId>formcycle-adapter-interface</artifactId> <name>EM - Formcycle Adapter - Interface</name> - <version>2.13.0-SNAPSHOT</version> + <version>2.15.0-SNAPSHOT</version> <properties> <vorgang-manager.version>2.0.0</vorgang-manager.version> diff --git a/formcycle-adapter/pom.xml b/formcycle-adapter/pom.xml index 6c060d69a936ed7a12926cd27db9f4788e720fb4..82c4f6bf13ce8340f6d24dd10a32103ed3f5fbfc 100644 --- a/formcycle-adapter/pom.xml +++ b/formcycle-adapter/pom.xml @@ -29,7 +29,7 @@ <parent> <groupId>de.ozgcloud.eingang</groupId> <artifactId>eingang-manager</artifactId> - <version>2.13.0-SNAPSHOT</version> + <version>2.15.0-SNAPSHOT</version> </parent> <artifactId>formcycle-adapter</artifactId> diff --git a/formsolutions-adapter/pom.xml b/formsolutions-adapter/pom.xml index 325327a0b108097786653edf290990debcae1c97..61a100c3ea25a117167baf6a2d84014a30d9cac3 100644 --- a/formsolutions-adapter/pom.xml +++ b/formsolutions-adapter/pom.xml @@ -30,7 +30,7 @@ <parent> <groupId>de.ozgcloud.eingang</groupId> <artifactId>eingang-manager</artifactId> - <version>2.13.0-SNAPSHOT</version> + <version>2.15.0-SNAPSHOT</version> <relativePath>../</relativePath> </parent> @@ -174,27 +174,14 @@ <groupId>pl.project13.maven</groupId> <artifactId>git-commit-id-plugin</artifactId> </plugin> - <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> - <configuration> - <image> - <!-- cann be removed when using common lib > 2.3.2--> - <builder>paketobuildpacks/builder-jammy-base</builder> - <env> - <BPE_DELIM_JAVA_TOOL_OPTIONS xml:space="preserve"> </BPE_DELIM_JAVA_TOOL_OPTIONS> - <BPE_APPEND_JAVA_TOOL_OPTIONS>-Dfile.encoding=UTF-8</BPE_APPEND_JAVA_TOOL_OPTIONS> - </env> - </image> - </configuration> - </plugin> - + </plugin> <plugin> <groupId>org.jacoco</groupId> <artifactId>jacoco-maven-plugin</artifactId> </plugin> - </plugins> </build> @@ -211,7 +198,7 @@ <id>build-image</id> <phase>install</phase> <goals> - <goal>build-image</goal> + <goal>build-image-no-fork</goal> </goals> </execution> </executions> diff --git a/forwarder/pom.xml b/forwarder/pom.xml index 39605a3df67fbdb757c543b6b89f4484b043dbb7..e0b5a6be46401028b29abd5a62ecf63cc59a8231 100644 --- a/forwarder/pom.xml +++ b/forwarder/pom.xml @@ -29,7 +29,7 @@ <parent> <groupId>de.ozgcloud.eingang</groupId> <artifactId>eingang-manager</artifactId> - <version>2.13.0-SNAPSHOT</version> + <version>2.15.0-SNAPSHOT</version> <relativePath>../</relativePath> </parent> diff --git a/intelliform-adapter/pom.xml b/intelliform-adapter/pom.xml index a3dfe80bb8058225d880fe2b0fb834ad91f00ab9..3d8c9820d3501241aa7d069deac51cd92bb3de93 100644 --- a/intelliform-adapter/pom.xml +++ b/intelliform-adapter/pom.xml @@ -31,7 +31,7 @@ <parent> <groupId>de.ozgcloud.eingang</groupId> <artifactId>eingang-manager</artifactId> - <version>2.13.0-SNAPSHOT</version> + <version>2.15.0-SNAPSHOT</version> <relativePath>../</relativePath> </parent> @@ -244,7 +244,7 @@ <id>build-image</id> <phase>install</phase> <goals> - <goal>build-image</goal> + <goal>build-image-no-fork</goal> </goals> </execution> </executions> diff --git a/intelliform-adapter/src/test/java/de/ozgcloud/eingang/intelliform/FormDataEndpointITCase.java b/intelliform-adapter/src/test/java/de/ozgcloud/eingang/intelliform/FormDataEndpointITCase.java index 54523201fd281dea6af56fdf32489b5e0ead3316..9860796131f316f3e145390f8c1b0de0f0d057b4 100644 --- a/intelliform-adapter/src/test/java/de/ozgcloud/eingang/intelliform/FormDataEndpointITCase.java +++ b/intelliform-adapter/src/test/java/de/ozgcloud/eingang/intelliform/FormDataEndpointITCase.java @@ -382,15 +382,6 @@ class FormDataEndpointITCase { assertThat(file.getContent().size()).isZero(); } - @Test - void checkForAttachmentFileContentStream() { - sendRequest(); - - var fileStream = formDataCaptor.getValue().getAttachments().get(0).getFiles().get(0).getContentStream(); - - assertThat(fileStream).isNotNull(); - } - @Test void checkAttachmentGroup2Count() { sendRequest(); @@ -437,14 +428,6 @@ class FormDataEndpointITCase { assertThat(file.getContent().size()).isZero(); } - @Test - void checkForRepresentationFileContentStream() { - sendRequest(); - - var fileStream = formDataCaptor.getValue().getRepresentations().get(0).getContentStream(); - - assertThat(fileStream).isNotNull(); - } } @DisplayName("service konto") diff --git a/intelliform-adapter/src/test/java/de/ozgcloud/eingang/intelliform/FormDataEndpointTest.java b/intelliform-adapter/src/test/java/de/ozgcloud/eingang/intelliform/FormDataEndpointTest.java index b58584e84b0ccf8362a448a506449d67bc7a23c2..caa77acc9a6d0b07d8d084c96ea7251df1341d96 100644 --- a/intelliform-adapter/src/test/java/de/ozgcloud/eingang/intelliform/FormDataEndpointTest.java +++ b/intelliform-adapter/src/test/java/de/ozgcloud/eingang/intelliform/FormDataEndpointTest.java @@ -64,15 +64,13 @@ class FormDataEndpointTest { } private Deposit buildRequest(String fileName) throws SAXException, IOException, ParserConfigurationException, URISyntaxException { - var depositData = new DepositData(); var attachment = new Attachment(); attachment.setName("XML-Daten.xml"); attachment.setContent(TestUtils.loadTextFile(fileName).getBytes()); - depositData.getAttachments() - .add(attachment); + depositData.getAttachments().add(attachment); var deposit = new Deposit(); deposit.setData(depositData); diff --git a/pom.xml b/pom.xml index e8c8ec64c40f1795975863be8bc7a4fe76ef4549..507bba28c75ff92d74e2dacf54de22bf169913ab 100644 --- a/pom.xml +++ b/pom.xml @@ -31,13 +31,13 @@ <parent> <groupId>de.ozgcloud.common</groupId> <artifactId>ozgcloud-common-parent</artifactId> - <version>4.3.1</version> + <version>4.7.0-SNAPSHOT</version> <relativePath/> <!-- lookup parent from repository --> </parent> <groupId>de.ozgcloud.eingang</groupId> <artifactId>eingang-manager</artifactId> - <version>2.13.0-SNAPSHOT</version> + <version>2.15.0-SNAPSHOT</version> <packaging>pom</packaging> <name>OZG-Cloud Eingang Manager</name> diff --git a/router/pom.xml b/router/pom.xml index 2ace78948a637913a36b0f781609cfaaca7843fb..92d6bf3f783ccc8dafc687ca6755e2891b980d5d 100644 --- a/router/pom.xml +++ b/router/pom.xml @@ -29,7 +29,7 @@ <parent> <groupId>de.ozgcloud.eingang</groupId> <artifactId>eingang-manager</artifactId> - <version>2.13.0-SNAPSHOT</version> + <version>2.15.0-SNAPSHOT</version> <relativePath>../</relativePath> </parent> diff --git a/router/src/main/java/de/ozgcloud/eingang/router/GrpcEingangMapper.java b/router/src/main/java/de/ozgcloud/eingang/router/GrpcEingangMapper.java index 74607f148396fb856dd86a4716f5f67f0d2f4019..c69b8397708151fa0c71aec866f6c2a5aeaceb4f 100644 --- a/router/src/main/java/de/ozgcloud/eingang/router/GrpcEingangMapper.java +++ b/router/src/main/java/de/ozgcloud/eingang/router/GrpcEingangMapper.java @@ -23,6 +23,7 @@ */ package de.ozgcloud.eingang.router; +import java.util.Optional; import java.util.UUID; import org.mapstruct.CollectionMappingStrategy; @@ -32,8 +33,6 @@ import org.mapstruct.NullValueCheckStrategy; import org.mapstruct.NullValuePropertyMappingStrategy; import org.mapstruct.ReportingPolicy; -import com.google.protobuf.ByteString; - import de.ozgcloud.eingang.common.formdata.Antragsteller; import de.ozgcloud.eingang.common.formdata.FormData; import de.ozgcloud.eingang.common.formdata.IncomingFileGroup; @@ -52,17 +51,17 @@ import de.ozgcloud.vorgang.vorgang.GrpcZustaendigeStelle; uses = { GrpcFormDataMapper.class, ServiceKontoMapper.class }) public interface GrpcEingangMapper { - @Mapping(source = "antragsteller.data", target = "antragsteller.otherData") - @Mapping(source = "attachments", target = "attachmentsList") - @Mapping(source = "representations", target = "representationsList") - GrpcEingang toEingang(FormData formData); - - default ByteString byteArrayToByteString(byte[] byteArray) { - if (byteArray == null) { - return null; - } + @Mapping(target = "antragsteller.otherData", source = "formData.antragsteller.data") + @Mapping(target = "attachmentsList", source = "formData.attachments") + @Mapping(target = "representationsList", source = "formData.representations") + @Mapping(target = "zustaendigeStelle", expression = "java( toZustaendigeStelle(getZustaendigeStelle(formData, organisationsEinheitenId)) )") + GrpcEingang toEingang(FormData formData, Optional<String> organisationsEinheitenId); - return ByteString.copyFrom(byteArray); + default ZustaendigeStelle getZustaendigeStelle(FormData formData, Optional<String> organisationsEinheitenId) { + return organisationsEinheitenId.flatMap(oeId -> formData.getZustaendigeStelles().stream() + .filter(zustaendigeStelle -> zustaendigeStelle.getOrganisationseinheitenId().equals(oeId)) + .findFirst()) + .orElseGet(() -> ZustaendigeStelle.builder().build()); } @Mapping(source = "files", target = "filesList") diff --git a/router/src/main/java/de/ozgcloud/eingang/router/VorgangRemoteService.java b/router/src/main/java/de/ozgcloud/eingang/router/VorgangRemoteService.java index 2a50225927053555819bbd1ac937ed0598088dd4..260cdc3818a4af61e2f93d632a66afb75a31062f 100644 --- a/router/src/main/java/de/ozgcloud/eingang/router/VorgangRemoteService.java +++ b/router/src/main/java/de/ozgcloud/eingang/router/VorgangRemoteService.java @@ -75,7 +75,7 @@ public class VorgangRemoteService { logConnection(organisationsEinheitenId, vorgangServiceStub.get()); try { - return createVorgang(formData, grpcEingangMapper.toEingang(formData), vorgangServiceStub.get(), binaryFileServiceStub.get()); + return createVorgang(formData, grpcEingangMapper.toEingang(formData, organisationsEinheitenId), vorgangServiceStub.get(), binaryFileServiceStub.get()); } finally { finishStubConnections(List.of(vorgangServiceStub, binaryFileServiceStub)); } @@ -159,7 +159,7 @@ public class VorgangRemoteService { } String uploadIncomingFile(IncomingFile incomingFile) { - var fileContentStream = incomingFile.getContentStreamForFinalRead(); + var fileContentStream = incomingFile.getContentStream(); var resultFuture = GrpcFileUploadUtils.createSender(this::buildChunkRequest, fileContentStream, this::buildCallStreamObserver) diff --git a/router/src/main/java/de/ozgcloud/eingang/router/VorgangService.java b/router/src/main/java/de/ozgcloud/eingang/router/VorgangService.java index de97243af9a356da303522e4555b1509b540dc16..a5ae891ce8936a906686b30057301f893e3da193 100644 --- a/router/src/main/java/de/ozgcloud/eingang/router/VorgangService.java +++ b/router/src/main/java/de/ozgcloud/eingang/router/VorgangService.java @@ -23,31 +23,86 @@ */ package de.ozgcloud.eingang.router; +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; import java.util.List; import java.util.Optional; +import java.util.stream.Stream; import org.springframework.stereotype.Service; import de.ozgcloud.eingang.common.formdata.FormData; import de.ozgcloud.eingang.common.formdata.FormHeader; +import de.ozgcloud.eingang.common.formdata.IncomingFile; +import de.ozgcloud.eingang.common.formdata.IncomingFileGroup; import de.ozgcloud.eingang.common.formdata.ServiceKonto; import de.ozgcloud.eingang.common.formdata.ZustaendigeStelle; import lombok.AllArgsConstructor; +import lombok.extern.log4j.Log4j2; @AllArgsConstructor @Service +@Log4j2 public class VorgangService { private final VorgangRemoteService remoteService; public String createVorgang(FormData formData) { - var preparedFormData = preserveConsistency(formData); + var vorgangId = createVorgangForOrganisationsEinheitIds(getOrganisationsEinheitIds(formData), preserveConsistency(formData)); + cleanupFormDataFiles(formData); + return vorgangId; + } + + void cleanupFormDataFiles(FormData formData) { + getFormDataFiles(formData) + .map(IncomingFile::getFile) + .map(File::toPath) + .forEach(this::deleteIncomingFile); + } + + void deleteIncomingFile(Path path) { + try { + Files.deleteIfExists(path); + } catch (IOException e) { + logErrorOnDeleteFailure(e); + } + } + + void logErrorOnDeleteFailure(Exception e) { + LOG.error("Failed to delete temp-file of incoming file!", e); + } + + Stream<IncomingFile> getFormDataFiles(FormData formData) { + return Stream.concat( + formData.getRepresentations().stream(), + formData.getAttachments().stream() + .map(IncomingFileGroup::getFiles) + .flatMap(List::stream) + ); + } + + String createVorgangForOrganisationsEinheitIds(List<String> organisationsEinheitIds, FormData preparedFormData) { + return organisationsEinheitIds.isEmpty() + ? createVorgangOnMissingZustaendigeStelle(preparedFormData) + : createMultipleVorgangs(preparedFormData, organisationsEinheitIds).getFirst(); + } + + String createVorgangOnMissingZustaendigeStelle(FormData formData) { + return remoteService.createVorgang(formData, Optional.empty()); + } - return remoteService.createVorgang(preparedFormData, getOrganisationsEinheitId(preparedFormData)); + List<String> createMultipleVorgangs(FormData formData, List<String> organisationseinheitIds) { + return organisationseinheitIds.stream() + .map(oeId -> remoteService.createVorgang(formData, Optional.of(oeId))) + .toList(); } - private Optional<String> getOrganisationsEinheitId(FormData formData) { - return Optional.ofNullable(formData.getZustaendigeStelle()).map(ZustaendigeStelle::getOrganisationseinheitenId); + List<String> getOrganisationsEinheitIds(FormData formData) { + return formData.getZustaendigeStelles().stream() + .map(ZustaendigeStelle::getOrganisationseinheitenId) + .toList(); } FormData preserveConsistency(FormData formData) { diff --git a/router/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/router/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports deleted file mode 100644 index 099d759980592d22435720bf65909618aa0d3c2a..0000000000000000000000000000000000000000 --- a/router/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports +++ /dev/null @@ -1,6 +0,0 @@ -net.devh.boot.grpc.client.autoconfigure.GrpcClientAutoConfiguration -net.devh.boot.grpc.client.autoconfigure.GrpcClientMetricAutoConfiguration -net.devh.boot.grpc.client.autoconfigure.GrpcClientHealthAutoConfiguration -net.devh.boot.grpc.client.autoconfigure.GrpcClientSecurityAutoConfiguration -net.devh.boot.grpc.client.autoconfigure.GrpcClientTraceAutoConfiguration -net.devh.boot.grpc.client.autoconfigure.GrpcDiscoveryClientAutoConfiguration \ No newline at end of file diff --git a/router/src/test/java/de/ozgcloud/eingang/router/GrpcEingangMapperITCase.java b/router/src/test/java/de/ozgcloud/eingang/router/GrpcEingangMapperITCase.java index 4150f6cef6d0574b78c6db89d9b61c068cd620e2..f3c15dea9839888f9895a6e440489ee6f09b9b8e 100644 --- a/router/src/test/java/de/ozgcloud/eingang/router/GrpcEingangMapperITCase.java +++ b/router/src/test/java/de/ozgcloud/eingang/router/GrpcEingangMapperITCase.java @@ -27,6 +27,7 @@ import static org.assertj.core.api.Assertions.*; import java.util.List; import java.util.Map; +import java.util.Optional; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayName; @@ -58,8 +59,7 @@ class GrpcEingangMapperITCase { @Test void antragstellerShouldBeMapped() { - - var antragSteller = grpcEingangMapper.toEingang(FormDataTestFactory.create()).getAntragsteller(); + var antragSteller = grpcEingangMapper.toEingang(FormDataTestFactory.create(), Optional.of(ZustaendigeStelleTestFactory.ORGANISATIONSEINHEIT_ID)).getAntragsteller(); assertThat(antragSteller.getPostfachId()).isEqualTo(AntragstellerTestFactory.POSTFACH_ID); assertThat(antragSteller.getVorname()).isEqualTo(AntragstellerTestFactory.VORNAME); @@ -68,8 +68,7 @@ class GrpcEingangMapperITCase { @Test void dataShouldBeMapped() { - - var antragsteller = grpcEingangMapper.toEingang(FormDataTestFactory.create()).getAntragsteller(); + var antragsteller = grpcEingangMapper.toEingang(FormDataTestFactory.create(), Optional.of(ZustaendigeStelleTestFactory.ORGANISATIONSEINHEIT_ID)).getAntragsteller(); assertThat(antragsteller.getOtherData().getFieldList()).hasSize(1); assertThat(antragsteller.getOtherData().getField(0).getName()).isEqualTo(AntragstellerTestFactory.GEBIET_BEZEICHNUNG_KEY); @@ -82,13 +81,21 @@ class GrpcEingangMapperITCase { class TestZustaendigeStelle { @Test void eingangShouldHaveZustaendigeStelle() { - - var zustaendigeStelle = grpcEingangMapper.toEingang(FormDataTestFactory.create()).getZustaendigeStelle(); + var zustaendigeStelle = grpcEingangMapper.toEingang(FormDataTestFactory.create(), Optional.of(ZustaendigeStelleTestFactory.ORGANISATIONSEINHEIT_ID)).getZustaendigeStelle(); assertThat(zustaendigeStelle).isNotNull(); assertThat(zustaendigeStelle.getOrganisationseinheitenId()).isEqualTo(ZustaendigeStelleTestFactory.ORGANISATIONSEINHEIT_ID); assertThat(zustaendigeStelle.getEmail()).isEqualTo(ZustaendigeStelleTestFactory.EMAIL); } + + @DisplayName("should map empty organisationeinheitId if missing") + @Test + void shouldMapEmptyOrganisationeinheitIdIfMissing() { + var zustaendigeStelle = grpcEingangMapper.toEingang(FormDataTestFactory.create(), Optional.empty()).getZustaendigeStelle(); + + assertThat(zustaendigeStelle).isNotNull(); + assertThat(zustaendigeStelle.getOrganisationseinheitenId()).isEmpty(); + } } @Nested @@ -100,7 +107,7 @@ class GrpcEingangMapperITCase { @BeforeEach void init() { - eingang = grpcEingangMapper.toEingang(FormDataTestFactory.create()); + eingang = grpcEingangMapper.toEingang(FormDataTestFactory.create(), Optional.empty()); } @Test @@ -159,7 +166,7 @@ class GrpcEingangMapperITCase { @Test void testRepresentations() { - GrpcEingang eingang = grpcEingangMapper.toEingang(FormDataTestFactory.create()); + GrpcEingang eingang = grpcEingangMapper.toEingang(FormDataTestFactory.create(), Optional.empty()); assertThat(eingang.getRepresentationsCount()).isEqualTo(1); @@ -180,7 +187,7 @@ class GrpcEingangMapperITCase { void valueListShouldGenerateFields() { GrpcEingang eingang = grpcEingangMapper - .toEingang(FormDataTestFactory.createBuilder().formData(Map.of("key", List.of("value1", "value2"))).build()); + .toEingang(FormDataTestFactory.createBuilder().formData(Map.of("key", List.of("value1", "value2"))).build(), Optional.empty()); assertThat(eingang.getFormData().getFieldCount()).isEqualTo(2); } @@ -190,7 +197,7 @@ class GrpcEingangMapperITCase { GrpcEingang eingang = grpcEingangMapper .toEingang(FormDataTestFactory.createBuilder() - .formData(Map.of("key-1", List.of(Map.of("sub_key", "value1"), Map.of("sub_key", "value2")))).build()); + .formData(Map.of("key-1", List.of(Map.of("sub_key", "value1"), Map.of("sub_key", "value2")))).build(), Optional.empty()); assertThat(eingang.getFormData().getFormCount()).isEqualTo(2); assertThat(eingang.getFormData().getForm(0).getFieldCount()).isEqualTo(1); diff --git a/router/src/test/java/de/ozgcloud/eingang/router/GrpcEingangMapperTest.java b/router/src/test/java/de/ozgcloud/eingang/router/GrpcEingangMapperTest.java index 3909125566b6f297d16633590aa4dcc05644611b..df68e82b76e4175a69dde4153eceb108cde21872 100644 --- a/router/src/test/java/de/ozgcloud/eingang/router/GrpcEingangMapperTest.java +++ b/router/src/test/java/de/ozgcloud/eingang/router/GrpcEingangMapperTest.java @@ -27,6 +27,8 @@ import static org.assertj.core.api.Assertions.*; import static org.mockito.ArgumentMatchers.*; import static org.mockito.Mockito.*; +import java.util.Optional; + import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Nested; @@ -212,7 +214,7 @@ class GrpcEingangMapperTest { } private GrpcEingang toEingang() { - return mapper.toEingang(FormDataTestFactory.create()); + return mapper.toEingang(FormDataTestFactory.create(), Optional.of(ZustaendigeStelleTestFactory.ORGANISATIONSEINHEIT_ID)); } } } \ No newline at end of file diff --git a/router/src/test/java/de/ozgcloud/eingang/router/VorgangRemoteServiceTest.java b/router/src/test/java/de/ozgcloud/eingang/router/VorgangRemoteServiceTest.java index 993c973ca2f71c645734db5ab5039151b9a0543f..0fd01eaa035fb5ceeb124fffc5f32e5dc66a0c2b 100644 --- a/router/src/test/java/de/ozgcloud/eingang/router/VorgangRemoteServiceTest.java +++ b/router/src/test/java/de/ozgcloud/eingang/router/VorgangRemoteServiceTest.java @@ -117,7 +117,7 @@ class VorgangRemoteServiceTest { when(resolver.resolveBinaryFileServiceStubByOrganisationsEinheitId(any())).thenReturn(managableBinaryFileServiceStub); when(managableBinaryFileServiceStub.get()).thenReturn(binaryFileServiceStub); - when(eingangMapper.toEingang(any())).thenReturn(eingang); + when(eingangMapper.toEingang(any(), any())).thenReturn(eingang); doNothing().when(remoteService).logConnection(any(), any()); doNothing().when(remoteService).finishStubConnections(any()); @@ -159,7 +159,7 @@ class VorgangRemoteServiceTest { void shouldCallEingangMapper() { createVorgang(); - verify(eingangMapper).toEingang(formData); + verify(eingangMapper).toEingang(formData, organisationsEinheitId); } @Test @@ -431,6 +431,55 @@ class VorgangRemoteServiceTest { } } + @DisplayName("update incoming file") + @Nested + class TestUpdateIncomingFile { + + @Mock + private IncomingFile incomingFile; + + @Mock + private InputStream inputStream; + + @Mock + private GrpcUploadBinaryFileResponse response; + + @Mock + private GrpcUploadBinaryFileRequest request; + + @BeforeEach + void mock() { + doReturn(response).when(vorgangCreator).waitUntilFutureToComplete(any(), any()); + when(incomingFile.getContentStream()).thenReturn(inputStream); + doReturn(request).when(vorgangCreator).buildMetaDataRequest(any()); + } + + @DisplayName("should call get content stream") + @Test + void shouldCallGetContentStream() { + vorgangCreator.uploadIncomingFile(incomingFile); + + verify(incomingFile).getContentStream(); + } + + @DisplayName("should call build request with incoming file") + @Test + void shouldCallBuildRequestWithIncomingFile() { + vorgangCreator.uploadIncomingFile(incomingFile); + + verify(vorgangCreator).buildMetaDataRequest(incomingFile); + } + + @DisplayName("should call wait until future complete") + @Test + void shouldCallWaitUntilFutureComplete() { + vorgangCreator.uploadIncomingFile(incomingFile); + + verify(vorgangCreator).waitUntilFutureToComplete(any(), eq(inputStream)); + } + + } + @Nested class TestWaitUntilFutureToComplete { diff --git a/router/src/test/java/de/ozgcloud/eingang/router/VorgangServiceTest.java b/router/src/test/java/de/ozgcloud/eingang/router/VorgangServiceTest.java index 2db3d04b7e3ad7bdb2240c7a1a66d8b39cbb4ca8..74cd1e901ea5260c9ab606fd0f7b00d00fd6fb23 100644 --- a/router/src/test/java/de/ozgcloud/eingang/router/VorgangServiceTest.java +++ b/router/src/test/java/de/ozgcloud/eingang/router/VorgangServiceTest.java @@ -23,11 +23,18 @@ */ package de.ozgcloud.eingang.router; +import static de.ozgcloud.eingang.common.formdata.FormDataTestFactory.*; +import static java.util.Collections.*; import static org.assertj.core.api.Assertions.*; import static org.junit.jupiter.api.Assertions.*; import static org.mockito.Mockito.*; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.List; import java.util.Optional; +import java.util.stream.Stream; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayName; @@ -41,6 +48,8 @@ import de.ozgcloud.eingang.common.formdata.FormData; import de.ozgcloud.eingang.common.formdata.FormDataTestFactory; import de.ozgcloud.eingang.common.formdata.FormHeader; import de.ozgcloud.eingang.common.formdata.FormHeaderTestFactory; +import de.ozgcloud.eingang.common.formdata.IncomingFile; +import de.ozgcloud.eingang.common.formdata.IncomingFileTestFactory; import de.ozgcloud.eingang.common.formdata.ServiceKonto; import de.ozgcloud.eingang.common.formdata.ServiceKontoTestFactory; import de.ozgcloud.eingang.common.formdata.ZustaendigeStelleTestFactory; @@ -51,20 +60,22 @@ class VorgangServiceTest { @InjectMocks private VorgangService service; @Mock - private GrpcEingangMapper eingangMapper; - @Mock private VorgangRemoteService remoteService; + private final FormData formData = FormDataTestFactory.create(); + @DisplayName("Create vorgang") @Nested class TestCreateVorgang { - - private final FormData formData = FormDataTestFactory.create(); private final FormData preservedFormData = FormDataTestFactory.create(); + private final List<String> organisationseinheitIds = List.of(ZustaendigeStelleTestFactory.ORGANISATIONSEINHEIT_ID); @BeforeEach void mockEingangMapper() { - doReturn(preservedFormData).when(service).preserveConsistency(formData); + doReturn(preservedFormData).when(service).preserveConsistency(any()); + doReturn(organisationseinheitIds).when(service).getOrganisationsEinheitIds(any()); + doReturn(VORGANG_ID).when(service).createVorgangForOrganisationsEinheitIds(any(), any()); + doNothing().when(service).cleanupFormDataFiles(any()); } @Test @@ -74,15 +85,231 @@ class VorgangServiceTest { verify(service).preserveConsistency(formData); } + @DisplayName("should call create vorgang for organisationseinheitIds") @Test - void shouldCallRemoteService() { + void shouldCallCreateVorgangForOrganisationseinheitIds() { callCreateVorgang(); - verify(remoteService).createVorgang(preservedFormData, Optional.ofNullable(ZustaendigeStelleTestFactory.ORGANISATIONSEINHEIT_ID)); + verify(service).createVorgangForOrganisationsEinheitIds(organisationseinheitIds, preservedFormData); + } + + @DisplayName("should call get organisationseinheit ids") + @Test + void shouldCallGetOrganisationseinheitIds() { + callCreateVorgang(); + + verify(service).getOrganisationsEinheitIds(formData); + } + + @DisplayName("should return vorgang id") + @Test + void shouldReturn() { + var vorgangId = callCreateVorgang(); + + assertThat(vorgangId).isEqualTo(VORGANG_ID); + } + + @DisplayName("should call cleanup form data files") + @Test + void shouldCallCleanupFormDataFiles() { + callCreateVorgang(); + + verify(service).cleanupFormDataFiles(formData); + } + + private String callCreateVorgang() { + return service.createVorgang(formData); + } + } + + @DisplayName("cleanup form data files") + @Nested + class TestCleanupFormDataFiles { + private final IncomingFile incomingFile = IncomingFileTestFactory.create(); + + @BeforeEach + void mock() { + doReturn(Stream.of(incomingFile)).when(service).getFormDataFiles(formData); + } + + @DisplayName("should call delete incoming file") + @Test + void shouldCallDeleteIncomingFile() { + service.cleanupFormDataFiles(formData); + + verify(service).deleteIncomingFile(incomingFile.getFile().toPath()); } + } + + @DisplayName("get form data files") + @Nested + class TestGetFormDataFiles { + + private final FormData formData = FormDataTestFactory.create(); + + @DisplayName("should return attachments and representations") + @Test + void shouldReturnAttachmentsAndRepresentations() { + var files = service.getFormDataFiles(formData).toList(); + + assertThat(files).hasSize(3); + } + } + + @DisplayName("delete incoming file") + @Nested + class TestDeleteIncomingFile { + + @Mock + private Path path; + + @DisplayName("should call deleteIfExists") + @Test + void shouldCallDeleteIfExists() { + try (var staticMock = mockStatic(Files.class)) { + service.deleteIncomingFile(path); + + staticMock.verify(() -> Files.deleteIfExists(path)); + } + } + + @DisplayName("should return") + @Test + void shouldReturn() { + try (var staticMock = mockStatic(Files.class)) { + staticMock.when(() -> Files.deleteIfExists(path)).thenReturn(true); + + service.deleteIncomingFile(path); + } + } + + @DisplayName("should log on error") + @Test + void shouldLogOnError() { + var exception = new IOException(); + try (var staticMock = mockStatic(Files.class)) { + staticMock.when(() -> Files.deleteIfExists(path)).thenThrow(exception); + + service.deleteIncomingFile(path); + + verify(service).logErrorOnDeleteFailure(exception); + } + } + + } + + @DisplayName("create vorgang for organisationsEinheitIds") + @Nested + class TestCreateVorgangForOrganisationsEinheitIds { + private final FormData preservedFormData = FormDataTestFactory.create(); + private final List<String> organisationseinheitIds = List.of(ZustaendigeStelleTestFactory.ORGANISATIONSEINHEIT_ID); + + @DisplayName("should call create multiple vorgangs") + @Test + void shouldCallCreateMultipleVorgangs() { + service.createVorgangForOrganisationsEinheitIds(organisationseinheitIds, preservedFormData); + + verify(service).createMultipleVorgangs(preservedFormData, organisationseinheitIds); + } + + @DisplayName("should return first vorgang id with multiple organisationseinheits") + @Test + void shouldReturnFirstVorgangIdWithMultipleOrganisationseinheits() { + doReturn(List.of(VORGANG_ID)).when(service).createMultipleVorgangs(any(), any()); + + var vorgangId = service.createVorgangForOrganisationsEinheitIds(organisationseinheitIds, preservedFormData); + + assertThat(vorgangId).isEqualTo(VORGANG_ID); + } + + @DisplayName("should call create vorgang on missing zustaendige stelle if organisationseinheit is missing") + @Test + void shouldCallCreateVorgangOnMissingZustaendigeStelleIfOrganisationseinheitIsMissing() { + service.createVorgangForOrganisationsEinheitIds(emptyList(), preservedFormData); + + verify(service).createVorgangOnMissingZustaendigeStelle(eq(preservedFormData)); + } + + @DisplayName("should return single vorgang id if organisationseinheit is missing") + @Test + void shouldReturnSingleVorgangIdIfOrganisationseinheitIsMissing() { + doReturn(VORGANG_ID).when(service).createVorgangOnMissingZustaendigeStelle(any()); + + var firstVorgangId = service.createVorgangForOrganisationsEinheitIds(emptyList(), preservedFormData); + + assertThat(firstVorgangId).isEqualTo(VORGANG_ID); + } + + } + + @DisplayName("create vorgang on missing zustaendige stelle") + @Nested + class TestVorgangOnMissingZustaendigeStelle { + @Mock + private FormData formData; + + @BeforeEach + void mock() { + when(remoteService.createVorgang(any(), any())).thenReturn(VORGANG_ID); + } + + @DisplayName("should call create vorgang") + @Test + void shouldCallCreateVorgang() { + service.createVorgangOnMissingZustaendigeStelle(formData); + + verify(remoteService).createVorgang(formData, Optional.empty()); + } + + @DisplayName("should return") + @Test + void shouldReturn() { + var vorgangId = service.createVorgangOnMissingZustaendigeStelle(formData); + + assertThat(vorgangId).isEqualTo(VORGANG_ID); + } + } + + @DisplayName("create multiple vorgangs") + @Nested + class TestCreateMultipleVorgangs { + + @Mock + private FormData formData; + + @BeforeEach + void mock() { + when(remoteService.createVorgang(any(), any())).thenReturn(VORGANG_ID); + } + + @DisplayName("should call create vorgang twice") + @Test + void shouldCallCreateVorgangTwice() { + service.createMultipleVorgangs(formData, List.of(ZustaendigeStelleTestFactory.ORGANISATIONSEINHEIT_ID)); + + verify(remoteService).createVorgang(formData, Optional.of(ZustaendigeStelleTestFactory.ORGANISATIONSEINHEIT_ID)); + } + + @DisplayName("should return") + @Test + void shouldReturn() { + var vorgangIds = service.createMultipleVorgangs(formData, List.of(ZustaendigeStelleTestFactory.ORGANISATIONSEINHEIT_ID)); + + assertThat(vorgangIds).containsExactly(VORGANG_ID); + } + } + + @DisplayName("get organisationseinheit ids") + @Nested + class TestGetOrganisationseinheitIds { + private final FormData preservedFormData = FormDataTestFactory.create(); + + @DisplayName("should return") + @Test + void shouldReturn() { + var organisationseinheitIds = service.getOrganisationsEinheitIds(preservedFormData); - private void callCreateVorgang() { - service.createVorgang(formData); + assertThat(organisationseinheitIds).containsExactly(ZustaendigeStelleTestFactory.ORGANISATIONSEINHEIT_ID); } } @@ -102,7 +329,7 @@ class VorgangServiceTest { assertThat(consistentFormData.getHeader().getServiceKonto()).isNull(); } - @DisplayName("should keep serviceKonto if postfachAddress eixsts") + @DisplayName("should keep serviceKonto if postfachAddress exists") @Test void shouldKeepServiceKonto() { var consistentFormData = service.preserveConsistency(FormDataTestFactory.create()); diff --git a/semantik-adapter/pom.xml b/semantik-adapter/pom.xml index 18c5fe1bb8ace2afd5e890daf9196ed782046a29..1bc88f3a6f599fa7cee5c72324e261b5c6fa2c9a 100644 --- a/semantik-adapter/pom.xml +++ b/semantik-adapter/pom.xml @@ -30,7 +30,7 @@ <parent> <groupId>de.ozgcloud.eingang</groupId> <artifactId>eingang-manager</artifactId> - <version>2.13.0-SNAPSHOT</version> + <version>2.15.0-SNAPSHOT</version> </parent> <artifactId>semantik-adapter</artifactId> diff --git a/semantik-adapter/src/main/java/de/ozgcloud/eingang/semantik/SemantikAdapter.java b/semantik-adapter/src/main/java/de/ozgcloud/eingang/semantik/SemantikAdapter.java index 9168807d8b4e2a6c52ae95c8bb509ffd04ecd1d8..65c69a87ebc51b3313b8b4ec84d24f7d10170cf0 100644 --- a/semantik-adapter/src/main/java/de/ozgcloud/eingang/semantik/SemantikAdapter.java +++ b/semantik-adapter/src/main/java/de/ozgcloud/eingang/semantik/SemantikAdapter.java @@ -34,7 +34,6 @@ import de.ozgcloud.eingang.semantik.enginebased.EngineBasedSemantikAdapter; import de.ozgcloud.eingang.semantik.formbased.FormBasedSemantikAdapter; import lombok.extern.log4j.Log4j2; - @Log4j2 @Service public class SemantikAdapter { diff --git a/semantik-adapter/src/main/java/de/ozgcloud/eingang/semantik/enginebased/afm/AfmZustaendigeStelleMapper.java b/semantik-adapter/src/main/java/de/ozgcloud/eingang/semantik/enginebased/afm/AfmZustaendigeStelleMapper.java index 1e057c6e81f5c937a429d8050c2c8996742026c9..4fff0ea90b799476bac4f0b3b3c39e4e8378935f 100644 --- a/semantik-adapter/src/main/java/de/ozgcloud/eingang/semantik/enginebased/afm/AfmZustaendigeStelleMapper.java +++ b/semantik-adapter/src/main/java/de/ozgcloud/eingang/semantik/enginebased/afm/AfmZustaendigeStelleMapper.java @@ -72,7 +72,9 @@ class AfmZustaendigeStelleMapper implements AfmEngineBasedMapper { .organisationseinheitenId(organisationseinheitenID) .build(); - return formData.toBuilder().formData(addMetaDataFlag(formData)).zustaendigeStelle(zustaendigeStelle).build(); + return formData.toBuilder() + .formData(addMetaDataFlag(formData)) + .zustaendigeStelle(zustaendigeStelle).build(); } String getOrganisationseinheitenId(FormData formData) { diff --git a/semantik-adapter/src/main/java/de/ozgcloud/eingang/semantik/enginebased/afm/ZustaendigeStelleMetadataMapper.java b/semantik-adapter/src/main/java/de/ozgcloud/eingang/semantik/enginebased/afm/ZustaendigeStelleMetadataMapper.java index 4b417bd36dc8421632a5e26447d1b7b669f249dd..a99ae318b214154314e9cf5752dcf13ce03d89fe 100644 --- a/semantik-adapter/src/main/java/de/ozgcloud/eingang/semantik/enginebased/afm/ZustaendigeStelleMetadataMapper.java +++ b/semantik-adapter/src/main/java/de/ozgcloud/eingang/semantik/enginebased/afm/ZustaendigeStelleMetadataMapper.java @@ -45,7 +45,8 @@ public class ZustaendigeStelleMetadataMapper { return formData.getRepresentations().stream().filter(IS_BEHOERDE_METADATA).findAny() .map(this::readZustaendigeStelleMetadata) .map(this::mapZustaendigeStelle) - .map(zustaendigeStelle -> formData.toBuilder().zustaendigeStelle(zustaendigeStelle).build()) + .map(zustaendigeStelle -> formData.toBuilder() + .zustaendigeStelle(zustaendigeStelle).build()) .orElse(formData); } diff --git a/semantik-adapter/src/main/java/de/ozgcloud/eingang/semantik/enginebased/dfoerdermittel/DFoerdermittelEngineBasedSemantikAdapter.java b/semantik-adapter/src/main/java/de/ozgcloud/eingang/semantik/enginebased/dfoerdermittel/DFoerdermittelEngineBasedSemantikAdapter.java index a89ba548f5247f858cea72a3443f89d5cd014cda..82d0967071bcfcabad3b9a7803d0e23c77e69a7a 100644 --- a/semantik-adapter/src/main/java/de/ozgcloud/eingang/semantik/enginebased/dfoerdermittel/DFoerdermittelEngineBasedSemantikAdapter.java +++ b/semantik-adapter/src/main/java/de/ozgcloud/eingang/semantik/enginebased/dfoerdermittel/DFoerdermittelEngineBasedSemantikAdapter.java @@ -2,6 +2,7 @@ package de.ozgcloud.eingang.semantik.enginebased.dfoerdermittel; import java.io.IOException; import java.io.InputStream; +import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.Map; @@ -100,22 +101,32 @@ public class DFoerdermittelEngineBasedSemantikAdapter implements EngineBasedSema FormData addOrganisationsEinheitId(FormData formData) { return Optional.ofNullable((String) getFachnachricht(formData).get(KEY_ORGANISATIONS_EINHEIT_ID)) - .map(orgaId -> addOrganisationsEinheitId(orgaId, formData.getZustaendigeStelle())) - .map(zustStelle -> formData.toBuilder().zustaendigeStelle(zustStelle).build()) + .map(orgaId -> addOrganisationsEinheitId(orgaId, formData.getZustaendigeStelles())) + .map(zustStelle -> formData.toBuilder() + .zustaendigeStelle(zustStelle) + .build()) .orElse(formData); } - private ZustaendigeStelle addOrganisationsEinheitId(String orgaId, ZustaendigeStelle zustaendigeStelle) { + private ZustaendigeStelle addOrganisationsEinheitId(String orgaId, Collection<ZustaendigeStelle> zustaendigeStelles) { ZustaendigeStelle.ZustaendigeStelleBuilder zustaendigeStelleBuilder; - if (Objects.isNull(zustaendigeStelle)) { + if (Objects.isNull(zustaendigeStelles) || zustaendigeStelles.isEmpty()) { zustaendigeStelleBuilder = ZustaendigeStelle.builder(); } else { + var zustaendigeStellesIterator = zustaendigeStelles.iterator(); + var zustaendigeStelle = zustaendigeStellesIterator.next(); + logErrorForExistingZustaendigeStelle(); zustaendigeStelleBuilder = zustaendigeStelle.toBuilder(); } return zustaendigeStelleBuilder.organisationseinheitenId(orgaId).build(); } + void logErrorForExistingZustaendigeStelle() { + LOG.error( + "Expect no existing ZustaendigeStelle for DFoerdermittel! Continuing with two ZustaendigeStelles, the original(s) and a copy of the first with overridden OrganisationsEinheitId."); + } + FormData addFormName(FormData formData) { return mapWithModifiedHeader(formData, headerBuilder -> headerBuilder.formName( getNonEmptyFachnachrichtValueByKey(formData, KEY_FORM_NAME) diff --git a/semantik-adapter/src/main/java/de/ozgcloud/eingang/semantik/formbased/mantelantrag/MantelantragZustaendigeStelleMapper.java b/semantik-adapter/src/main/java/de/ozgcloud/eingang/semantik/formbased/mantelantrag/MantelantragZustaendigeStelleMapper.java index 29e2c0834d9a05e11519f371cdd2686faa549ed4..d7fa85a1d87e3ac6776068e6a5a062a8b96de3d3 100644 --- a/semantik-adapter/src/main/java/de/ozgcloud/eingang/semantik/formbased/mantelantrag/MantelantragZustaendigeStelleMapper.java +++ b/semantik-adapter/src/main/java/de/ozgcloud/eingang/semantik/formbased/mantelantrag/MantelantragZustaendigeStelleMapper.java @@ -18,7 +18,6 @@ import org.springframework.boot.context.properties.bind.Binder; import org.springframework.core.env.Environment; import org.springframework.stereotype.Component; -import de.ozgcloud.eingang.common.errorhandling.TechnicalException; import de.ozgcloud.eingang.common.formdata.FormData; import de.ozgcloud.eingang.common.formdata.FormHeader; import de.ozgcloud.eingang.common.formdata.ZustaendigeStelle; @@ -67,78 +66,52 @@ public class MantelantragZustaendigeStelleMapper implements FormBasedMapper { @Override public FormData parseFormData(FormData formData) { - try { - return adaptFormDataWithPossibleException(formData); - } catch (TechnicalException exception) { - logWarningForFailure(exception); - return formData; - } + return formData.toBuilder() + .clearZustaendigeStelles() + .zustaendigeStelles(getZustaendigeStelles(formData)) + .build(); } - void logWarningForFailure(Exception exception) { - LOG.warn("Failed mapping Zustaendigestelle of Mantelantrag: %s".formatted(exception.getMessage())); + List<ZustaendigeStelle> getZustaendigeStelles(FormData formData) { + var fieldMap = formData.getFormData(); + var matchingSlots = getMatchingSlots(fieldMap); + if (matchingSlots.isEmpty()) { + logErrorForNoMatchingIdentifiers(); + } + return matchingSlots.stream() + .map(slotIndex -> getZustaendigeStelle(fieldMap, slotIndex)) + .toList(); } - FormData adaptFormDataWithPossibleException(FormData formData) { - var fieldMap = formData.getFormData(); - var slotIndex = findSlotIndex(fieldMap); - return adaptFormDataWithValueGetter(formData, field -> getFieldByKeyOrEmpty( + ZustaendigeStelle getZustaendigeStelle(Map<String, Object> fieldMap, int slotIndex) { + UnaryOperator<String> getValueOrEmpty = field -> getFieldByKeyOrEmpty( fieldMap, getNameForSlotIndex(field, slotIndex) - )); - } - - private FormData adaptFormDataWithValueGetter(FormData formData, UnaryOperator<String> getValueOrEmpty) { - return formData.toBuilder() - .zustaendigeStelle(ZustaendigeStelle.builder() - .organisationseinheitenId(getOrganisationseinheitId(getValueOrEmpty)) - .bezeichnung(getValueOrEmpty.apply(BEZEICHNUNG_FIELD)) - .email(getValueOrEmpty.apply(EMAIL_FIELD)) - .hausanschriftStrasse(getValueOrEmpty.apply(HAUSANSCHRIFT_STRASSE_FIELD)) - .hausanschriftPlz(getValueOrEmpty.apply(HAUSANSCHRIFT_PLZ_FIELD)) - .hausanschriftOrt(getValueOrEmpty.apply(HAUSANSCHRIFT_ORT_FIELD)) - .telefon(getValueOrEmpty.apply(TELEFON_FIELD)) - .build()) - .build(); - } - - private String getOrganisationseinheitId(UnaryOperator<String> getValueOrEmpty) { + ); var organisationseinheitId = getValueOrEmpty.apply(ORGANISATIONSEINHEIT_ID_FIELD); - if (organisationseinheitId.isBlank()) { - throw new TechnicalException("OrganistaionseinheitId not found!"); - } - - return organisationseinheitId; - } - - int findSlotIndex(Map<String, Object> fieldMap) { - var matchingSlots = getMatchingSlots(fieldMap); - verifyOneMatchingIdentifier(matchingSlots); - return matchingSlots.getFirst(); - } - - private void verifyOneMatchingIdentifier(List<Integer> matchingSlots) { - if (matchingSlots.size() != 1) { - var message = getMultipleSlotsMessage(matchingSlots); - if (matchingSlots.isEmpty()) { - throw new TechnicalException(message); - } else { - logWarningForUnexpected(message); - } + logWarningForEmptyOrganisationseinheitId(slotIndex); } + return ZustaendigeStelle.builder() + .organisationseinheitenId(organisationseinheitId) + .bezeichnung(getValueOrEmpty.apply(BEZEICHNUNG_FIELD)) + .email(getValueOrEmpty.apply(EMAIL_FIELD)) + .hausanschriftStrasse(getValueOrEmpty.apply(HAUSANSCHRIFT_STRASSE_FIELD)) + .hausanschriftPlz(getValueOrEmpty.apply(HAUSANSCHRIFT_PLZ_FIELD)) + .hausanschriftOrt(getValueOrEmpty.apply(HAUSANSCHRIFT_ORT_FIELD)) + .telefon(getValueOrEmpty.apply(TELEFON_FIELD)) + .build(); } - void logWarningForUnexpected(String message) { - LOG.warn("Unexpected Zustaendigestelle in Mantelantrag: %s".formatted(message)); + void logWarningForEmptyOrganisationseinheitId(int slotIndex) { + LOG.warn("[Mantelantrag] OrganisationseinheitId for slot {} is empty!", slotIndex); } - String getMultipleSlotsMessage(List<Integer> matchingSlots) { - return "Found %d matching nachrichtenbroker addresses! Expected one of '%s'.".formatted(matchingSlots.size(), - Strings.join(xtaIdentifiers, ',')); + void logErrorForNoMatchingIdentifiers() { + LOG.error("[Mantelantrag] No matching Zustaendigestelle found! For identifiers: '{}'.", Strings.join(xtaIdentifiers, ',')); } - private List<Integer> getMatchingSlots(Map<String, Object> fieldMap) { + List<Integer> getMatchingSlots(Map<String, Object> fieldMap) { return IntStream.range(0, 3) .filter(slotIndex -> xtaIdentifiers.contains(getXtaIdentifierOfSlot(fieldMap, slotIndex))) .boxed() diff --git a/semantik-adapter/src/test/java/de/ozgcloud/eingang/semantik/SemantikAdapterTest.java b/semantik-adapter/src/test/java/de/ozgcloud/eingang/semantik/SemantikAdapterTest.java index 754667f0298c9d867846cafee6f28d6b82677fd2..ea63f2379a7391af25178495e00d3af611cb04e4 100644 --- a/semantik-adapter/src/test/java/de/ozgcloud/eingang/semantik/SemantikAdapterTest.java +++ b/semantik-adapter/src/test/java/de/ozgcloud/eingang/semantik/SemantikAdapterTest.java @@ -23,6 +23,7 @@ */ package de.ozgcloud.eingang.semantik; +import static de.ozgcloud.eingang.common.formdata.FormDataTestFactory.*; import static org.assertj.core.api.Assertions.*; import static org.mockito.ArgumentMatchers.*; import static org.mockito.Mockito.*; @@ -98,6 +99,7 @@ class SemantikAdapterTest { doReturn(List.of(engineAdapter)).when(adapter).getResponsibleEngineAdapters(formData); when(engineAdapter.parseFormData(any())).thenReturn(engineAdapterResponse); when(formAdapter.parseFormData(any())).thenReturn(formAdapterResponse); + when(vorgangService.createVorgang(any())).thenReturn(VORGANG_ID); } @Test @@ -127,5 +129,13 @@ class SemantikAdapterTest { verify(vorgangService).createVorgang(formAdapterResponse); } + + @DisplayName("should return first vorgang id") + @Test + void shouldReturnFirstVorgangId() { + var vorgangId = adapter.processFormData(formData); + + assertThat(vorgangId).isEqualTo(VORGANG_ID); + } } } diff --git a/semantik-adapter/src/test/java/de/ozgcloud/eingang/semantik/enginebased/FilesMapperHelperTest.java b/semantik-adapter/src/test/java/de/ozgcloud/eingang/semantik/enginebased/FilesMapperHelperTest.java index cfbf8d3481cd4679412ceceb84f886152467c30a..0375100ea49c6ac7f0c68bdff8a41d8d988bd3ad 100644 --- a/semantik-adapter/src/test/java/de/ozgcloud/eingang/semantik/enginebased/FilesMapperHelperTest.java +++ b/semantik-adapter/src/test/java/de/ozgcloud/eingang/semantik/enginebased/FilesMapperHelperTest.java @@ -171,7 +171,7 @@ class FilesMapperHelperTest { assertThat(cleanedFormData.getId()).isEqualTo(formData.getId()); assertThat(cleanedFormData.getHeader()).isEqualTo(formData.getHeader()); - assertThat(cleanedFormData.getZustaendigeStelle()).isEqualTo(formData.getZustaendigeStelle()); + assertThat(cleanedFormData.getZustaendigeStelles()).isEqualTo(formData.getZustaendigeStelles()); assertThat(cleanedFormData.getAntragsteller()).isEqualTo(formData.getAntragsteller()); assertThat(cleanedFormData.getNumberOfAttachments()).isEqualTo(formData.getNumberOfAttachments()); assertThat(cleanedFormData.getAttachments()).isEqualTo(formData.getAttachments()); diff --git a/semantik-adapter/src/test/java/de/ozgcloud/eingang/semantik/enginebased/afm/AfmZustaendigeStelleMapperTest.java b/semantik-adapter/src/test/java/de/ozgcloud/eingang/semantik/enginebased/afm/AfmZustaendigeStelleMapperTest.java index 4f83cb409499a33c332c3b8226012cf210949ae8..e9abbeff9c2dc8b2af9f03c35006fe667cc3acbc 100644 --- a/semantik-adapter/src/test/java/de/ozgcloud/eingang/semantik/enginebased/afm/AfmZustaendigeStelleMapperTest.java +++ b/semantik-adapter/src/test/java/de/ozgcloud/eingang/semantik/enginebased/afm/AfmZustaendigeStelleMapperTest.java @@ -37,6 +37,7 @@ import org.mockito.Spy; import de.ozgcloud.eingang.common.formdata.FormData; import de.ozgcloud.eingang.common.formdata.FormDataTestFactory; +import de.ozgcloud.eingang.common.formdata.ZustaendigeStelle; class AfmZustaendigeStelleMapperTest { @@ -78,22 +79,27 @@ class AfmZustaendigeStelleMapperTest { void shouldMapOrganisationseinheitenId() { var parsedFormData = parseZustaendigeStelleData(formData); - assertThat(parsedFormData.getZustaendigeStelle().getOrganisationseinheitenId()) - .isEqualTo(AfmZustaendigeStelleTestFactory.ORGANISATIONSEINHEITEN_ID); + assertThat(parsedFormData.getZustaendigeStelles()) + .extracting(ZustaendigeStelle::getOrganisationseinheitenId) + .containsExactly(AfmZustaendigeStelleTestFactory.ORGANISATIONSEINHEITEN_ID); } @Test void shouldMapBezeichnung() { var parsedFormData = parseZustaendigeStelleData(formData); - assertThat(parsedFormData.getZustaendigeStelle().getBezeichnung()).isEqualTo(BEZEICHNUNG); + assertThat(parsedFormData.getZustaendigeStelles()) + .extracting(ZustaendigeStelle::getBezeichnung) + .containsExactly(BEZEICHNUNG); } @Test void shouldMapEmail() { var parsedFormData = parseZustaendigeStelleData(formData); - assertThat(parsedFormData.getZustaendigeStelle().getEmail()).isEqualTo(AfmZustaendigeStelleTestFactory.EMAIL); + assertThat(parsedFormData.getZustaendigeStelles()) + .extracting(ZustaendigeStelle::getEmail) + .containsExactly(AfmZustaendigeStelleTestFactory.EMAIL); } @Test diff --git a/semantik-adapter/src/test/java/de/ozgcloud/eingang/semantik/enginebased/afm/ZustaendigeStelleMetadataMapperTest.java b/semantik-adapter/src/test/java/de/ozgcloud/eingang/semantik/enginebased/afm/ZustaendigeStelleMetadataMapperTest.java index 5da34d86397802416e222b17f31722392944791d..56058ec127401eeff1744df316e1aa60ef62449e 100644 --- a/semantik-adapter/src/test/java/de/ozgcloud/eingang/semantik/enginebased/afm/ZustaendigeStelleMetadataMapperTest.java +++ b/semantik-adapter/src/test/java/de/ozgcloud/eingang/semantik/enginebased/afm/ZustaendigeStelleMetadataMapperTest.java @@ -44,7 +44,7 @@ class ZustaendigeStelleMetadataMapperTest { behoerdeMetadataFile = IncomingFileTestFactory.createBuilder().name(ZustaendigeStelleMetadataMapper.BEHOERDE_METADATA_FILE_NAME) .build(); formData = FormDataTestFactory.createBuilder() - .zustaendigeStelle(null) + .clearZustaendigeStelles() .representation(behoerdeMetadataFile).build(); } @@ -76,17 +76,15 @@ class ZustaendigeStelleMetadataMapperTest { var result = mapper.parseZustaendigeStelleData(formData); - assertThat(result.getZustaendigeStelle()).isEqualTo(zustaendigeStelle); + assertThat(result.getZustaendigeStelles()).containsExactly(zustaendigeStelle); } } @Nested class TestReadBehoerdeMetadata { - private File brokenFile; - } @Nested diff --git a/semantik-adapter/src/test/java/de/ozgcloud/eingang/semantik/enginebased/dfoerdermittel/DFoerdermittelEngineBasedSemantikAdapterTest.java b/semantik-adapter/src/test/java/de/ozgcloud/eingang/semantik/enginebased/dfoerdermittel/DFoerdermittelEngineBasedSemantikAdapterTest.java index 2445fe3b2f3f7119bc53e33031595a02e6b7c20c..512d0a840d9c9018c5eb0b3c81495b470636f8e1 100644 --- a/semantik-adapter/src/test/java/de/ozgcloud/eingang/semantik/enginebased/dfoerdermittel/DFoerdermittelEngineBasedSemantikAdapterTest.java +++ b/semantik-adapter/src/test/java/de/ozgcloud/eingang/semantik/enginebased/dfoerdermittel/DFoerdermittelEngineBasedSemantikAdapterTest.java @@ -27,6 +27,7 @@ import de.ozgcloud.eingang.common.formdata.PostfachAddressTestFactory; import de.ozgcloud.eingang.common.formdata.ServiceKontoTestFactory; import de.ozgcloud.eingang.common.formdata.StringBasedIdentifier; import de.ozgcloud.eingang.common.formdata.ZustaendigeStelle; +import de.ozgcloud.eingang.common.formdata.ZustaendigeStelleTestFactory; import de.ozgcloud.eingang.semantik.common.ServiceKontoFactory; class DFoerdermittelEngineBasedSemantikAdapterTest { @@ -217,12 +218,44 @@ class DFoerdermittelEngineBasedSemantikAdapterTest { @Nested class TestAddOrganisationsEinheitId { - @Test - void shouldHaveOrganisationsEinheitId() { - var formData = adapter.addOrganisationsEinheitId(DFoerdermittelFormDataTestFactory.create()); - assertThat(formData.getZustaendigeStelle()).isNotNull().extracting(ZustaendigeStelle::getOrganisationseinheitenId) - .isEqualTo(ORGANISATIONS_EINHEIT_ID); + @DisplayName("with no existing zustaendige stelles") + @Nested + class TestWithNoExistingZustaendigeStelles { + @Test + void shouldHaveOrganisationsEinheitId() { + var inputFormData = DFoerdermittelFormDataTestFactory.createBuilder() + .clearZustaendigeStelles() + .build(); + + var formData = adapter.addOrganisationsEinheitId(inputFormData); + + assertThat(formData.getZustaendigeStelles()) + .extracting(ZustaendigeStelle::getOrganisationseinheitenId) + .containsExactly(ORGANISATIONS_EINHEIT_ID); + } + } + + @DisplayName("with one existing zustaendige stelle") + @Nested + class TestWithOneExistingZustaendigeStelle { + + @Test + void shouldHaveOrganisationsEinheitId() { + var formData = adapter.addOrganisationsEinheitId(DFoerdermittelFormDataTestFactory.create()); + + assertThat(formData.getZustaendigeStelles()) + .extracting(ZustaendigeStelle::getOrganisationseinheitenId) + .containsExactly(ZustaendigeStelleTestFactory.ORGANISATIONSEINHEIT_ID, ORGANISATIONS_EINHEIT_ID); + } + + @DisplayName("should log error for existing zustaendige stelle") + @Test + void shouldLogErrorForExistingZustaendigeStelle() { + adapter.addOrganisationsEinheitId(DFoerdermittelFormDataTestFactory.create()); + + verify(adapter).logErrorForExistingZustaendigeStelle(); + } } } diff --git a/semantik-adapter/src/test/java/de/ozgcloud/eingang/semantik/enginebased/dfoerdermittel/DFoerdermittelFormDataTestFactory.java b/semantik-adapter/src/test/java/de/ozgcloud/eingang/semantik/enginebased/dfoerdermittel/DFoerdermittelFormDataTestFactory.java index 8b8c9bf4103b13f085a7910361925a11e7b90297..7bd4cc6a52d36405595a47500be02c2919066c6f 100644 --- a/semantik-adapter/src/test/java/de/ozgcloud/eingang/semantik/enginebased/dfoerdermittel/DFoerdermittelFormDataTestFactory.java +++ b/semantik-adapter/src/test/java/de/ozgcloud/eingang/semantik/enginebased/dfoerdermittel/DFoerdermittelFormDataTestFactory.java @@ -8,6 +8,7 @@ import java.util.function.Predicate; import java.util.stream.IntStream; import de.ozgcloud.eingang.common.formdata.FormData; +import de.ozgcloud.eingang.common.formdata.FormDataTestFactory; import de.ozgcloud.eingang.common.formdata.FormHeaderTestFactory; import lombok.Builder; @@ -35,7 +36,7 @@ class DFoerdermittelFormDataTestFactory { } static FormData.FormDataBuilder createBuilderWithFachnachricht(Fachnachricht fachnachricht) { - return FormData.builder() + return FormDataTestFactory.createBuilder() .header(FormHeaderTestFactory.create()) .formData(Map.of("Fachnachricht", createFachnachrichtMapWithFachnachricht(fachnachricht))); } diff --git a/semantik-adapter/src/test/java/de/ozgcloud/eingang/semantik/enginebased/formsolutions/FormSolutionsEngineBasedAdapterITCase.java b/semantik-adapter/src/test/java/de/ozgcloud/eingang/semantik/enginebased/formsolutions/FormSolutionsEngineBasedAdapterITCase.java index 47c563508627226dac6341fe8d6e4b36f9062b70..b0535b604a7120b70b0b8803c8003cc038cb9ae1 100644 --- a/semantik-adapter/src/test/java/de/ozgcloud/eingang/semantik/enginebased/formsolutions/FormSolutionsEngineBasedAdapterITCase.java +++ b/semantik-adapter/src/test/java/de/ozgcloud/eingang/semantik/enginebased/formsolutions/FormSolutionsEngineBasedAdapterITCase.java @@ -50,6 +50,7 @@ import de.ozgcloud.eingang.common.formdata.FormData; import de.ozgcloud.eingang.common.formdata.FormDataTestFactory; import de.ozgcloud.eingang.common.formdata.IncomingFileGroupTestFactory; import de.ozgcloud.eingang.common.formdata.IncomingFileTestFactory; +import de.ozgcloud.eingang.common.formdata.ZustaendigeStelle; import de.ozgcloud.eingang.semantik.SemantikAdapter; import lombok.SneakyThrows; @@ -236,14 +237,16 @@ public class FormSolutionsEngineBasedAdapterITCase { void shouldMap() { var data = engineAdapter.parseFormData(formData); - assertThat(data.getZustaendigeStelle()).isNotNull(); + assertThat(data.getZustaendigeStelles()).isNotNull().isNotEmpty(); } @Test void shouldMapOrganistaionseinheitenId() { var data = engineAdapter.parseFormData(formData); - assertThat(data.getZustaendigeStelle().getOrganisationseinheitenId()).isEqualTo("test"); + assertThat(data.getZustaendigeStelles()) + .extracting(ZustaendigeStelle::getOrganisationseinheitenId) + .containsExactly("test"); } } } diff --git a/semantik-adapter/src/test/java/de/ozgcloud/eingang/semantik/enginebased/formsolutions/FormSolutionsZustaendigeStelleMapperTest.java b/semantik-adapter/src/test/java/de/ozgcloud/eingang/semantik/enginebased/formsolutions/FormSolutionsZustaendigeStelleMapperTest.java index 1e019f49a47345092a4c9c2b5e6196871c621417..bd31c4218074b8bc343d3327e10455885df7371a 100644 --- a/semantik-adapter/src/test/java/de/ozgcloud/eingang/semantik/enginebased/formsolutions/FormSolutionsZustaendigeStelleMapperTest.java +++ b/semantik-adapter/src/test/java/de/ozgcloud/eingang/semantik/enginebased/formsolutions/FormSolutionsZustaendigeStelleMapperTest.java @@ -37,7 +37,6 @@ import org.mockito.Spy; import de.ozgcloud.eingang.common.formdata.FormData; import de.ozgcloud.eingang.common.formdata.FormDataTestFactory; -import de.ozgcloud.eingang.semantik.enginebased.formsolutions.FormSolutionsZustaendigeStelleMapper; class FormSolutionsZustaendigeStelleMapperTest { @@ -53,7 +52,6 @@ class FormSolutionsZustaendigeStelleMapperTest { @BeforeEach void setup() { formData = FormDataTestFactory.createBuilder() - .zustaendigeStelle(null) .formData(Map.of( FormDataTestFactory.SIMPLE_VALUE_KEY, FormDataTestFactory.SIMPLE_VALUE, FormSolutionsZustaendigeStelleMapper.ZUSTAENDIGE_STELLE, ORGANISATIONSEINHEIT_ID)) @@ -64,7 +62,7 @@ class FormSolutionsZustaendigeStelleMapperTest { void shouldParseFormData() { var resultFormData = mapper.parseFormData(formData); - assertThat(resultFormData.getZustaendigeStelle().getOrganisationseinheitenId()).isEqualTo(ORGANISATIONSEINHEIT_ID); + assertThat(resultFormData.getZustaendigeStelles().getFirst().getOrganisationseinheitenId()).isEqualTo(ORGANISATIONSEINHEIT_ID); assertThat(resultFormData.getFormData()).doesNotContainKey(ZUSTAENDIGE_STELLE); } @@ -73,7 +71,7 @@ class FormSolutionsZustaendigeStelleMapperTest { void shouldNotChangeAnother() { var resultFormData = mapper.parseFormData(formData); - assertThat(resultFormData).usingRecursiveComparison().ignoringFields("zustaendigeStelle", "formData").isEqualTo(formData); + assertThat(resultFormData).usingRecursiveComparison().ignoringFields("zustaendigeStelles", "formData").isEqualTo(formData); assertThat(resultFormData.getFormData()) .containsAllEntriesOf(Map.of(FormDataTestFactory.SIMPLE_VALUE_KEY, FormDataTestFactory.SIMPLE_VALUE)); } diff --git a/semantik-adapter/src/test/java/de/ozgcloud/eingang/semantik/formbased/mantelantrag/MantelantragITCase.java b/semantik-adapter/src/test/java/de/ozgcloud/eingang/semantik/formbased/mantelantrag/MantelantragITCase.java index a4951086c82837ebc3c01ef5f19b8833882b0e3c..e80eeca2598ef00dc45d827401744d80eb10ba4c 100644 --- a/semantik-adapter/src/test/java/de/ozgcloud/eingang/semantik/formbased/mantelantrag/MantelantragITCase.java +++ b/semantik-adapter/src/test/java/de/ozgcloud/eingang/semantik/formbased/mantelantrag/MantelantragITCase.java @@ -1,5 +1,6 @@ package de.ozgcloud.eingang.semantik.formbased.mantelantrag; +import static de.ozgcloud.eingang.common.formdata.FormDataTestFactory.*; import static org.assertj.core.api.Assertions.*; import static org.mockito.ArgumentMatchers.*; import static org.mockito.Mockito.*; @@ -7,69 +8,154 @@ import static org.mockito.Mockito.*; import java.io.File; import java.nio.file.Files; import java.nio.file.Path; +import java.util.Collections; import java.util.List; +import java.util.Optional; +import org.junit.jupiter.api.BeforeAll; +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.ArgumentCaptor; import org.mockito.Captor; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.test.mock.mockito.MockBean; import org.springframework.boot.test.mock.mockito.SpyBean; import org.springframework.test.context.ActiveProfiles; +import org.springframework.test.context.DynamicPropertyRegistry; +import org.springframework.test.context.DynamicPropertySource; import de.ozgcloud.common.binaryfile.TempFileUtils; import de.ozgcloud.common.test.TestUtils; import de.ozgcloud.eingang.Application; import de.ozgcloud.eingang.common.formdata.FormData; import de.ozgcloud.eingang.common.formdata.IncomingFileTestFactory; -import de.ozgcloud.eingang.router.VorgangService; +import de.ozgcloud.eingang.router.VorgangRemoteService; import de.ozgcloud.eingang.semantik.SemantikAdapter; import de.ozgcloud.eingang.semantik.enginebased.formsolutions.FormSolutionsEngineBasedAdapterITCase; import lombok.SneakyThrows; @ActiveProfiles({ "local", "itcase" }) -@SpringBootTest(classes = Application.class, properties = { "ozgcloud.xta.identifiers=afmsh:ozg-cloud-utopia-test" }) +@SpringBootTest(classes = Application.class) public class MantelantragITCase { private static final String FILE_NAME_XDOMEA = "mantelantrag/4620-EH6C_b3c9168a-6ae9-4361-8b2f-6837bb341021_Geschaeftsgang.Geschaeftsgang.0201.xml"; private static final String FILE_NAME_MANTELANTRAG = "mantelantrag/4620-EH6C_7d703670-15b6-42b2-8cd1-88a7e4c494b9_Antrag_Max_Mustermann_SGBXII.xml"; @MockBean - VorgangService vorgangService; + VorgangRemoteService vorgangRemoteService; @SpyBean SemantikAdapter semantikAdapter; + @Captor + ArgumentCaptor<FormData> formDataCaptor; + private FormData formData; + + @Captor + ArgumentCaptor<Optional<String>> oeIdCaptor; + + @Autowired + MantelantragZustaendigeStelleMapper mantelantragZustaendigeStelleMapper; + + static List<String> xtaIdentifiers = Collections.emptyList(); + + @BeforeEach + void mock() { + clearInvocations(vorgangRemoteService); + doReturn(VORGANG_ID).when(vorgangRemoteService).createVorgang(any(FormData.class), any()); + formData = prepareTestData(); + mantelantragZustaendigeStelleMapper.init(); + } + + @DynamicPropertySource + static void dynamicProperties(DynamicPropertyRegistry registry) { + registry.add("ozgcloud.xta.identifiers", () -> xtaIdentifiers); + } + + @DisplayName("without matching zustaendige stelle") @Nested - class TestZustaendigeStelle { + class TestWithoutMatchingZustaendigeStelle { - @Captor - ArgumentCaptor<FormData> formDataCaptor; + @BeforeAll + static void setup() { + xtaIdentifiers = List.of("afmsh:unknown"); + } + + @DisplayName("should create one vorgang") + @Test + void shouldCreateOneVorgang() { + semantikAdapter.processFormData(formData); + + verify(vorgangRemoteService, times(1)).createVorgang(formDataCaptor.capture(), oeIdCaptor.capture()); + assertThat(oeIdCaptor.getValue()).isEmpty(); + } + } + + @DisplayName("with one matching zustaendige stelle") + @Nested + class TestWithOneMatchingZustaendigeStelle { + @BeforeAll + static void setup() { + xtaIdentifiers = List.of("afmsh:ozg-cloud-utopia-test"); + } + @DisplayName("should create one vorgang") @Test - void zustaendigeStelleExists() { - var formData = prepareTestData(); - doReturn("test").when(vorgangService).createVorgang(any(FormData.class)); + void shouldCreateOneVorgang() { semantikAdapter.processFormData(formData); - verify(vorgangService).createVorgang(formDataCaptor.capture()); - FormData capturedFormData = formDataCaptor.getValue(); - assertThat(capturedFormData).isNotNull(); + verify(vorgangRemoteService, times(1)).createVorgang(formDataCaptor.capture(), oeIdCaptor.capture()); + assertThat(oeIdCaptor.getValue()).contains("123"); } + } + @DisplayName("with two matching zustaendige stelle") + @Nested + class TestWithTwoMatchingZustaendigeStelle { + + @BeforeAll + static void setup() { + xtaIdentifiers = List.of("afmsh:ozg-cloud-utopia-test", "gae:ozg-cloud-itcase-test"); + } + + @DisplayName("should create two vorangs with partially matching zustaendigeStelle") @Test - void zustaendigeStelleIsUtopia() { - var formData = prepareTestData(); - doReturn("test").when(vorgangService).createVorgang(any(FormData.class)); + void shouldCreateTwoVorangsWithPartiallyMatchingZustaendigeStelle() { semantikAdapter.processFormData(formData); - verify(vorgangService).createVorgang(formDataCaptor.capture()); - FormData capturedFormData = formDataCaptor.getValue(); + verify(vorgangRemoteService, times(2)).createVorgang(formDataCaptor.capture(), oeIdCaptor.capture()); + assertThat(oeIdCaptor.getAllValues()).contains(Optional.of("123"), Optional.of("444")); + } + } - assertThat(capturedFormData.getZustaendigeStelle().getOrganisationseinheitenId()).isEqualTo("123"); + @DisplayName("with three matching zustaendige stelles") + @Nested + class TestWithThreeMatchingZustaendigeStelles { + + @BeforeAll + static void setup() { + xtaIdentifiers = List.of("afmsh:ozg-cloud-utopia-test", "gae:ozg-cloud-itcase-test", "afmsh:ozg-cloud-bad-segeberg-kreis"); + } + + @DisplayName("should create three vorgangs") + @Test + void shouldCreateThreeVorgangs() { + semantikAdapter.processFormData(formData); + + verify(vorgangRemoteService, times(3)).createVorgang(formDataCaptor.capture(), oeIdCaptor.capture()); + assertThat(oeIdCaptor.getAllValues()).contains(Optional.of("123"), Optional.of("321"), Optional.of("444")); } + } + + @DisplayName("should return first vorgangId") + @Test + void shouldReturnFirstVorgangId() { + var result = semantikAdapter.processFormData(formData); + assertThat(result).isEqualTo(VORGANG_ID); } private FormData prepareTestData() { diff --git a/semantik-adapter/src/test/java/de/ozgcloud/eingang/semantik/formbased/mantelantrag/MantelantragZustaendigeStelleMapperTest.java b/semantik-adapter/src/test/java/de/ozgcloud/eingang/semantik/formbased/mantelantrag/MantelantragZustaendigeStelleMapperTest.java index ffc88cabe17fb7e087abab038e13dfff3b8b14d1..782209dff8ebd6174a29942c0812b90f8b5753ca 100644 --- a/semantik-adapter/src/test/java/de/ozgcloud/eingang/semantik/formbased/mantelantrag/MantelantragZustaendigeStelleMapperTest.java +++ b/semantik-adapter/src/test/java/de/ozgcloud/eingang/semantik/formbased/mantelantrag/MantelantragZustaendigeStelleMapperTest.java @@ -1,6 +1,7 @@ package de.ozgcloud.eingang.semantik.formbased.mantelantrag; import static de.ozgcloud.eingang.semantik.formbased.mantelantrag.MantelantragZustaendigeStelleMapper.*; +import static java.util.Collections.*; import static org.assertj.core.api.Assertions.*; import static org.mockito.Mockito.*; @@ -18,13 +19,10 @@ import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.MethodSource; import org.junit.jupiter.params.provider.ValueSource; -import org.mockito.ArgumentCaptor; -import org.mockito.Captor; import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.Spy; -import de.ozgcloud.eingang.common.errorhandling.TechnicalException; import de.ozgcloud.eingang.common.formdata.FormData; import de.ozgcloud.eingang.common.formdata.FormDataTestFactory; import de.ozgcloud.eingang.common.formdata.FormHeaderTestFactory; @@ -107,53 +105,104 @@ class MantelantragZustaendigeStelleMapperTest { } } - @DisplayName("adapt form data") + @DisplayName("parse form data") @Nested - class TestAdaptFormData { + class TestParseFormData { + + private FormData formData; @Mock + private ZustaendigeStelle zustaendigeStelle; + + @BeforeEach + void mock() { + formData = FormDataTestFactory.create(); + } + + @DisplayName("should override zustaendige stelles") + @Test + void shouldOverrideZustaendigeStelles() { + doReturn(List.of(zustaendigeStelle)).when(mapper).getZustaendigeStelles(formData); + + var result = mapper.parseFormData(formData); + + assertThat(result.getZustaendigeStelles()).containsExactly(zustaendigeStelle); + } + + @DisplayName("should keep other formdata fields") + @Test + void shouldKeepOtherFormdataFields() { + doReturn(formData.getZustaendigeStelles()).when(mapper).getZustaendigeStelles(formData); + + var result = mapper.parseFormData(formData); + + assertThat(result).usingRecursiveComparison().isEqualTo(formData); + } + } + + @DisplayName("get zustaendige stelles") + @Nested + class TestGetZustaendigeStelles { + private FormData formData; @Mock - private FormData formData2; + private Map<String, Object> fieldMap; + + @Mock + private ZustaendigeStelle stelle1; + + @Mock + private ZustaendigeStelle stelle2; + + @Mock + private ZustaendigeStelle stelle3; - @DisplayName("should return adapted value") + @BeforeEach + void mock() { + formData = FormDataTestFactory.createBuilder() + .formData(fieldMap) + .build(); + } + + @DisplayName("should return") @Test - void shouldReturnAdaptedValue() { - doReturn(formData2).when(mapper).adaptFormDataWithPossibleException(formData); + void shouldReturn() { + doReturn(emptyList()).when(mapper).getMatchingSlots(fieldMap); - var resultFormData = mapper.parseFormData(formData); + var result = mapper.getZustaendigeStelles(formData); - assertThat(resultFormData).isEqualTo(formData2); + assertThat(result).isEmpty(); } - @DisplayName("should return original value with exception") + @DisplayName("should log error for no matching identifiers") @Test - void shouldReturnOriginalValueWithException() { - doThrow(new TechnicalException("some error")).when(mapper).adaptFormDataWithPossibleException(formData); + void shouldLogErrorForNoMatchingIdentifiers() { + doReturn(emptyList()).when(mapper).getMatchingSlots(fieldMap); - var resultFormData = mapper.parseFormData(formData); + mapper.getZustaendigeStelles(formData); - assertThat(resultFormData).isEqualTo(formData); + verify(mapper).logErrorForNoMatchingIdentifiers(); } - @DisplayName("should log warning with exception") + @DisplayName("should return with three zustaendige stelle") @Test - void shouldLogWarningWithException() { - var exception = new TechnicalException("some error"); - doThrow(exception).when(mapper).adaptFormDataWithPossibleException(formData); + void shouldReturnWithThreeZustaendigeStelle() { + doReturn(List.of(0, 1, 2)).when(mapper).getMatchingSlots(fieldMap); + doReturn(stelle1).when(mapper).getZustaendigeStelle(fieldMap, 0); + doReturn(stelle2).when(mapper).getZustaendigeStelle(fieldMap, 1); + doReturn(stelle3).when(mapper).getZustaendigeStelle(fieldMap, 2); - mapper.parseFormData(formData); + var result = mapper.getZustaendigeStelles(formData); - verify(mapper).logWarningForFailure(exception); + assertThat(result).containsExactly(stelle1, stelle2, stelle3); } } - @DisplayName("adapt form data with possible exception") + @DisplayName("get zustaendige stelle") @Nested - class TestAdaptFormDataWithPossibleException { + class TestGetZustaendigeStelle { - static final String TARGET_OPTIONAL_FIELD_VALUE = "optionalFieldValue"; static final Map<String, Function<ZustaendigeStelle, String>> FIELD_NAME_TO_EXPECTED_VALUE_EXTRACTOR = Map.of( BEZEICHNUNG_FIELD, ZustaendigeStelle::getBezeichnung, EMAIL_FIELD, ZustaendigeStelle::getEmail, @@ -162,17 +211,8 @@ class MantelantragZustaendigeStelleMapperTest { HAUSANSCHRIFT_ORT_FIELD, ZustaendigeStelle::getHausanschriftOrt, TELEFON_FIELD, ZustaendigeStelle::getTelefon ); - private FormData formData; private Map<String, Object> fieldMap; - private static Stream<Arguments> fieldNameAndSlotIndex() { - return Stream.of(0, 1, 2) - .flatMap(slotIndex -> FIELD_NAME_TO_EXPECTED_VALUE_EXTRACTOR - .keySet().stream() - .map(fieldName -> Arguments.of(slotIndex, fieldName)) - ); - } - @BeforeEach void mock() { fieldMap = new HashMap<>(Map.of( @@ -180,21 +220,6 @@ class MantelantragZustaendigeStelleMapperTest { getOrganisationseinheitIDFieldName(2), "", getOrganisationseinheitIDFieldName(10), "1111111" )); - formData = FormDataTestFactory.createBuilder() - .formData(fieldMap) - .build(); - } - - @DisplayName("should keep form data except zustaendigestelle") - @Test - void shouldKeepFormDataExceptZustaendigestelle() { - doReturn(10).when(mapper).findSlotIndex(fieldMap); - - var resultFormData = mapper.parseFormData(formData); - - assertThat(resultFormData.getId()).isEqualTo(formData.getId()); - assertThat(resultFormData.getHeader()).isEqualTo(formData.getHeader()); - assertThat(resultFormData.getAntragsteller()).isEqualTo(formData.getAntragsteller()); } @DisplayName("should map organisationseinheitId") @@ -203,7 +228,7 @@ class MantelantragZustaendigeStelleMapperTest { void shouldMapOrganisationseinheitId(int slotIndex) { mockWithOEID(slotIndex, TARGET_OEID); - var zustaendigeStelle = getAdaptedZustaendigeStelle(); + var zustaendigeStelle = getZustaendigeStelle(slotIndex); assertThat(zustaendigeStelle.getOrganisationseinheitenId()).isEqualTo(TARGET_OEID); } @@ -212,62 +237,60 @@ class MantelantragZustaendigeStelleMapperTest { return mapper.getNameForSlotIndex(ORGANISATIONSEINHEIT_ID_FIELD, slotIndex); } - @DisplayName("should throw if organistaionseinheitId is missing") + @DisplayName("should log warning if organistaionseinheitId is missing") @ParameterizedTest @ValueSource(ints = { 0, 1, 2 }) - void shouldThrowIfOrganistationseinheitIdIsMissing(int slotIndex) { - doReturn(slotIndex).when(mapper).findSlotIndex(fieldMap); + void shouldLogWarningIfOrganistaionseinheitIdIsMissing(int slotIndex) { + getZustaendigeStelle(slotIndex); - assertThatThrownBy(this::getAdaptedZustaendigeStelle) - .isInstanceOf(TechnicalException.class); - } - - @DisplayName("should throw if organistationseinheitId is empty") - @ParameterizedTest - @ValueSource(ints = { 0, 1, 2 }) - void shouldThrowIfOrganistationseinheitIdIsEmpty(int slotIndex) { - mockWithOEID(slotIndex, ""); - - assertThatThrownBy(this::getAdaptedZustaendigeStelle) - .isInstanceOf(TechnicalException.class); + verify(mapper).logWarningForEmptyOrganisationseinheitId(slotIndex); } @DisplayName("should map optional field") @ParameterizedTest - @MethodSource("fieldNameAndSlotIndex") + @MethodSource("generateFieldNameAndSlotIndex") void shouldMapOptionalField(int slotIndex, String fieldName) { mockWithSomeOEID(slotIndex); - fieldMap.put(mapper.getNameForSlotIndex(fieldName, slotIndex), TARGET_OPTIONAL_FIELD_VALUE); + var optionalFieldValue = "value of '%s'".formatted(fieldName); + fieldMap.put(mapper.getNameForSlotIndex(fieldName, slotIndex), optionalFieldValue); - var zustaendigeStelle = getAdaptedZustaendigeStelle(); + var zustaendigeStelle = getZustaendigeStelle(slotIndex); - assertThat(getExpectedByFieldName(zustaendigeStelle, fieldName)).isEqualTo(TARGET_OPTIONAL_FIELD_VALUE); + assertThat(getExpectedValueByFieldName(zustaendigeStelle, fieldName)).isEqualTo(optionalFieldValue); } @DisplayName("should map missing optional fields to empty") @ParameterizedTest - @MethodSource("fieldNameAndSlotIndex") + @MethodSource("generateFieldNameAndSlotIndex") void shouldMapMissingOptionalFieldsToEmpty(int slotIndex, String fieldName) { mockWithSomeOEID(slotIndex); - var zustaendigeStelle = getAdaptedZustaendigeStelle(); + var zustaendigeStelle = getZustaendigeStelle(slotIndex); - assertThat(getExpectedByFieldName(zustaendigeStelle, fieldName)).isEmpty(); + assertThat(getExpectedValueByFieldName(zustaendigeStelle, fieldName)).isEmpty(); } @DisplayName("should map empty optional fields to empty") @ParameterizedTest - @MethodSource("fieldNameAndSlotIndex") + @MethodSource("generateFieldNameAndSlotIndex") void shouldMapEmptyOptionalFieldsToEmpty(int slotIndex, String fieldName) { mockWithSomeOEID(slotIndex); fieldMap.put(mapper.getNameForSlotIndex(fieldName, slotIndex), ""); - var zustaendigeStelle = getAdaptedZustaendigeStelle(); + var zustaendigeStelle = getZustaendigeStelle(slotIndex); - assertThat(getExpectedByFieldName(zustaendigeStelle, fieldName)).isEmpty(); + assertThat(getExpectedValueByFieldName(zustaendigeStelle, fieldName)).isEmpty(); } - private String getExpectedByFieldName(ZustaendigeStelle zustaendigeStelle, String fieldName) { + private static Stream<Arguments> generateFieldNameAndSlotIndex() { + return Stream.of(0, 1, 2) + .flatMap(slotIndex -> FIELD_NAME_TO_EXPECTED_VALUE_EXTRACTOR + .keySet().stream() + .map(fieldName -> Arguments.of(slotIndex, fieldName)) + ); + } + + private String getExpectedValueByFieldName(ZustaendigeStelle zustaendigeStelle, String fieldName) { var valueExtractor = FIELD_NAME_TO_EXPECTED_VALUE_EXTRACTOR.get(fieldName); return valueExtractor.apply(zustaendigeStelle); } @@ -278,25 +301,20 @@ class MantelantragZustaendigeStelleMapperTest { private void mockWithOEID(int slotIndex, String targetOeid) { fieldMap.put(getOrganisationseinheitIDFieldName(slotIndex), targetOeid); - doReturn(slotIndex).when(mapper).findSlotIndex(fieldMap); } - private ZustaendigeStelle getAdaptedZustaendigeStelle() { - var formDataResult = mapper.adaptFormDataWithPossibleException(formData); - return formDataResult.getZustaendigeStelle(); + private ZustaendigeStelle getZustaendigeStelle(int slotIndex) { + return mapper.getZustaendigeStelle(fieldMap, slotIndex); } } - @DisplayName("find slot index") + @DisplayName("get matching slots") @Nested - class TestFindSlotIndex { + class TestGetMatchingSlots { private Map<String, Object> fieldMap; - @Captor - private ArgumentCaptor<String> warningCaptor; - @BeforeEach void mock() { fieldMap = new HashMap<>(Map.of( @@ -305,15 +323,23 @@ class MantelantragZustaendigeStelleMapperTest { )); } - @DisplayName("should return matching slot") + @DisplayName("should return empty") + @Test + void shouldReturnEmpty() { + var resultSlotIndices = mapper.getMatchingSlots(fieldMap); + + assertThat(resultSlotIndices).isEmpty(); + } + + @DisplayName("should return matching slots") @ParameterizedTest @ValueSource(ints = { 0, 1, 2 }) void shouldReturnMatchingSlot(int slotIndex) { fieldMap.put(getZustaendigeStelleName(slotIndex), IDENTIFIER); - var resultSlotIndex = mapper.findSlotIndex(fieldMap); + var resultSlotIndices = mapper.getMatchingSlots(fieldMap); - assertThat(resultSlotIndex).isEqualTo(slotIndex); + assertThat(resultSlotIndices).containsExactly(slotIndex); } @DisplayName("should return matching slot with upper-/lowercase difference in identifiers") @@ -322,33 +348,14 @@ class MantelantragZustaendigeStelleMapperTest { void shouldReturnMatchingSlotWithUppercaseIdentifier(int slotIndex) { fieldMap.put(getZustaendigeStelleName(slotIndex), IDENTIFIER2UPPERCASE); - var resultSlotIndex = mapper.findSlotIndex(fieldMap); + var resultSlotIndex = mapper.getMatchingSlots(fieldMap); - assertThat(resultSlotIndex).isEqualTo(slotIndex); + assertThat(resultSlotIndex).containsExactly(slotIndex); } private String getZustaendigeStelleName(int slotIndex) { return mapper.getNameForSlotIndex(ZUSTELLUNG_NACHRICHTENBROKER_FIELD, slotIndex); } - - @DisplayName("should throw if no slot matches") - @Test - void shouldThrowIfNoSlotMatches() { - assertThatThrownBy(() -> mapper.findSlotIndex(fieldMap)) - .isInstanceOf(TechnicalException.class); - } - - @DisplayName("should log warning if multiple slots match") - @Test - void shouldLogWarningIfMultipleSlotsMatch() { - fieldMap.put(getZustaendigeStelleName(0), IDENTIFIER2); - fieldMap.put(getZustaendigeStelleName(2), IDENTIFIER); - - mapper.findSlotIndex(fieldMap); - - verify(mapper).logWarningForUnexpected(warningCaptor.capture()); - assertThat(warningCaptor.getValue()).isEqualTo(mapper.getMultipleSlotsMessage(List.of(0, 2))); - } } @DisplayName("get name for slot index") diff --git a/semantik-adapter/src/test/resources/mantelantrag/4620-EH6C_7d703670-15b6-42b2-8cd1-88a7e4c494b9_Antrag_Max_Mustermann_SGBXII.xml b/semantik-adapter/src/test/resources/mantelantrag/4620-EH6C_7d703670-15b6-42b2-8cd1-88a7e4c494b9_Antrag_Max_Mustermann_SGBXII.xml index dfe5df9a75784d09bed9a8b2d7a6506822906f0f..e45f08045f677cb400a0cf815f69bc2ec9468f68 100644 --- a/semantik-adapter/src/test/resources/mantelantrag/4620-EH6C_7d703670-15b6-42b2-8cd1-88a7e4c494b9_Antrag_Max_Mustermann_SGBXII.xml +++ b/semantik-adapter/src/test/resources/mantelantrag/4620-EH6C_7d703670-15b6-42b2-8cd1-88a7e4c494b9_Antrag_Max_Mustermann_SGBXII.xml @@ -83,7 +83,7 @@ <zustellung_nachrichtenbroker2>afmsh:ozg-cloud-bad-segeberg-kreis</zustellung_nachrichtenbroker2> <zustellung_email_ln2/> <zustellung_webservice2/> - <kontaktsystem_oeid3/> + <kontaktsystem_oeid3>444</kontaktsystem_oeid3> <OrganisationseinheitenBEZEICHNUNG3/> <zust_strasse3/> <zust_hausnummer3/> @@ -93,7 +93,7 @@ <zust_telefonnummer3/> <zust_faxnummer3/> <zust_emailadresse3/> - <zustellung_nachrichtenbroker3/> + <zustellung_nachrichtenbroker3>gae:ozg-cloud-itcase-test</zustellung_nachrichtenbroker3>> <zustellung_email_ln3/> <zustellung_webservice3/> <grund>Hilfe</grund> diff --git a/src/main/helm/templates/deployment.yaml b/src/main/helm/templates/deployment.yaml index c68b9d69be88de512c6cca216e756aad79d6f46f..b59bb1cc41fbfbba0098590a4986042bd510300e 100644 --- a/src/main/helm/templates/deployment.yaml +++ b/src/main/helm/templates/deployment.yaml @@ -79,7 +79,7 @@ spec: - name: ozgcloud_adapter_targetVorgangManagerName value: {{ (.Values.routing).targetVorgangManagerName}} - name: grpc_client_vorgang-manager-{{ (.Values.routing).targetVorgangManagerName}}_address - value: 'vorgang-manager.{{ coalesce (.Values.routing).targetNamespace .Release.Namespace }}:9090' + value: 'dns:///vorgang-manager.{{ coalesce (.Values.routing).targetNamespace .Release.Namespace }}:9090' - name: grpc_client_vorgang-manager-{{ (.Values.routing).targetVorgangManagerName}}_negotiationType value: {{ (.Values.routing).negotiationType | default "TLS" }} {{- end }} diff --git a/src/test/helm/deployment_routing_strategy_env_test.yaml b/src/test/helm/deployment_routing_strategy_env_test.yaml index 8ae56386a24a3f0f74e3bdb3395b2aed9f4d2be4..e70cff6f10669ad7574fb80dcbf96f3c11aee715 100644 --- a/src/test/helm/deployment_routing_strategy_env_test.yaml +++ b/src/test/helm/deployment_routing_strategy_env_test.yaml @@ -50,6 +50,12 @@ tests: content: name: grpc_client_vorgang-manager-vorgang-manager_negotiationType value: TLS + - contains: + path: spec.template.spec.containers[0].env + content: + name: grpc_client_vorgang-manager-vorgang-manager_address + value: dns:///vorgang-manager.sh-helm-test:9090 + - it: validate routing infos set: routing: diff --git a/src/test/helm/ingress_create_or_not.yaml b/src/test/helm/ingress_create_or_not_test.yaml similarity index 100% rename from src/test/helm/ingress_create_or_not.yaml rename to src/test/helm/ingress_create_or_not_test.yaml diff --git a/src/test/helm/ingress_nginx_tests.yaml b/src/test/helm/ingress_nginx_test.yaml similarity index 100% rename from src/test/helm/ingress_nginx_tests.yaml rename to src/test/helm/ingress_nginx_test.yaml diff --git a/xta-adapter/pom.xml b/xta-adapter/pom.xml index e96fb6c3dd46267839a27a0e6c9b19dea237b91d..8c519d2ecfa0697c6d3d6018a97aa4a697dc06a7 100644 --- a/xta-adapter/pom.xml +++ b/xta-adapter/pom.xml @@ -4,7 +4,7 @@ <parent> <groupId>de.ozgcloud.eingang</groupId> <artifactId>eingang-manager</artifactId> - <version>2.13.0-SNAPSHOT</version> + <version>2.15.0-SNAPSHOT</version> </parent> <artifactId>xta-adapter</artifactId> <name>Eingangs Adapter - XTA</name> @@ -168,6 +168,7 @@ </plugin> </plugins> </build> + <profiles> <profile> <id>ci-build</id> @@ -181,7 +182,7 @@ <id>build-image</id> <phase>install</phase> <goals> - <goal>build-image</goal> + <goal>build-image-no-fork</goal> </goals> </execution> </executions> diff --git a/xta-adapter/src/main/helm/templates/xta_adapter_cronjob.yaml b/xta-adapter/src/main/helm/templates/xta_adapter_cronjob.yaml index 3835e3ec440eebbd71cdb1bb5c21bf366add83c6..761959137f507e67d20c246ec86bc7393c52a75d 100644 --- a/xta-adapter/src/main/helm/templates/xta_adapter_cronjob.yaml +++ b/xta-adapter/src/main/helm/templates/xta_adapter_cronjob.yaml @@ -81,7 +81,7 @@ spec: - name: ozgcloud_adapter_targetVorgangManagerName value: {{ (.Values.routing).targetVorgangManagerName}} - name: grpc_client_vorgang-manager-{{ (.Values.routing).targetVorgangManagerName }}_address - value: 'vorgang-manager.{{ coalesce (.Values.routing).targetNamespace .Release.Namespace }}:9090' + value: 'dns:///vorgang-manager.{{ coalesce (.Values.routing).targetNamespace .Release.Namespace }}:9090' - name: grpc_client_vorgang-manager-{{ (.Values.routing).targetVorgangManagerName }}_negotiationType value: {{ (.Values.routing).negotiationType | default "PLAINTEXT" }} {{- end }} diff --git a/xta-adapter/src/main/java/de/ozgcloud/eingang/xta/XtaIncomingFilesMapper.java b/xta-adapter/src/main/java/de/ozgcloud/eingang/xta/XtaIncomingFilesMapper.java index 8041810ed8fbc3222fd10c06a4e64a6a760e9bf4..891512d2f4b878594ee813dbe3cdf5d9c4bfdb4c 100644 --- a/xta-adapter/src/main/java/de/ozgcloud/eingang/xta/XtaIncomingFilesMapper.java +++ b/xta-adapter/src/main/java/de/ozgcloud/eingang/xta/XtaIncomingFilesMapper.java @@ -26,10 +26,8 @@ package de.ozgcloud.eingang.xta; import java.util.Collection; import java.util.List; import java.util.Objects; -import java.util.function.Predicate; import java.util.stream.Stream; -import de.ozgcloud.eingang.common.formdata.IncomingFileGroup; import org.springframework.stereotype.Component; import de.ozgcloud.eingang.common.formdata.IncomingFile; @@ -44,14 +42,11 @@ class XtaIncomingFilesMapper { private final ZipFileExtractor zipFileExtractor; - public static final String ZIP_CONTENT_TYPE = "application/zip"; - static final Predicate<IncomingFile> IS_ZIP_FILE = contentType -> ZIP_CONTENT_TYPE.equals(contentType.getContentType()); - public List<IncomingFile> toIncomingFiles(Collection<XtaFile> messageFiles) { if (Objects.nonNull(messageFiles)) { return messageFiles.stream() .map(this::toIncomingFile) - .flatMap(this::extractZip) + .flatMap(this::tryToExtractZip) .toList(); } return List.of(); @@ -66,16 +61,11 @@ class XtaIncomingFilesMapper { .build(); } - Stream<IncomingFile> extractZip(IncomingFile incomingFile) { - if (IS_ZIP_FILE.test(incomingFile)) { - try { - List<IncomingFile> extractedZips = zipFileExtractor.extractIncomingFilesSafely(incomingFile); - return extractedZips.stream(); - } catch (RuntimeException e) { - LOG.error("Cannot read source ZIP. Not extracting file", e); - return Stream.of(incomingFile); - } - } else { + Stream<IncomingFile> tryToExtractZip(IncomingFile incomingFile) { + try { + List<IncomingFile> extractedZips = zipFileExtractor.extractIncomingFilesSafely(incomingFile); + return extractedZips.stream(); + } catch (RuntimeException e) { return Stream.of(incomingFile); } } diff --git a/xta-adapter/src/main/java/de/ozgcloud/eingang/xta/XtaMessage.java b/xta-adapter/src/main/java/de/ozgcloud/eingang/xta/XtaMessage.java index bb048d1c60c284da67062008acfdb6d5b1972281..2f51bd853ba2b95d58481319c083bc20f089c94f 100644 --- a/xta-adapter/src/main/java/de/ozgcloud/eingang/xta/XtaMessage.java +++ b/xta-adapter/src/main/java/de/ozgcloud/eingang/xta/XtaMessage.java @@ -9,6 +9,8 @@ import lombok.Singular; @Builder(toBuilder = true) @Getter public class XtaMessage { + private String primaryFormDataMessage; + private XtaMessageMetaData metaData; @Singular private Collection<XtaFile> messageFiles; diff --git a/xta-adapter/src/main/java/de/ozgcloud/eingang/xta/XtaMessageMapper.java b/xta-adapter/src/main/java/de/ozgcloud/eingang/xta/XtaMessageMapper.java index 09d353faf28d73111a2696cfc89e47978f9d07b4..7fb082ce762666db56da08c5734d9517738ef1a0 100644 --- a/xta-adapter/src/main/java/de/ozgcloud/eingang/xta/XtaMessageMapper.java +++ b/xta-adapter/src/main/java/de/ozgcloud/eingang/xta/XtaMessageMapper.java @@ -1,15 +1,18 @@ package de.ozgcloud.eingang.xta; +import java.util.Optional; + import org.mapstruct.Context; import org.mapstruct.Mapper; import org.mapstruct.Mapping; import de.ozgcloud.eingang.common.formdata.FormData; import de.ozgcloud.eingang.common.formdata.FormHeader; +import de.ozgcloud.eingang.common.formdata.FormMetaData; import de.ozgcloud.eingang.common.vorgang.VorgangNummerSupplier; import de.ozgcloud.eingang.semantik.enginebased.FilesMapperHelper; -@Mapper(imports = {FilesMapperHelper.class, XtaMapperHelper.class}) +@Mapper(imports = { FilesMapperHelper.class, XtaMapperHelper.class }) interface XtaMessageMapper { int VORGANG_NUMMER_SUFFIX_LENGTH = 4; @@ -22,6 +25,7 @@ interface XtaMessageMapper { @Mapping(target = "numberOfRepresentations", dependsOn = "representations", expression = "java(representationsAttachmentsPair.representations().size())") @Mapping(target = "representation", ignore = true) @Mapping(target = "attachment", ignore = true) + @Mapping(target = "control.metaData", source = "metaData") FormData toFormData(RepresentationsAttachmentsPair representationsAttachmentsPair, XtaMessageMetaData metaData, @Context VorgangNummerSupplier vorgangNummerSupplier); @@ -39,4 +43,8 @@ interface XtaMessageMapper { default String fromId(XtaMessageId id) { return id.toString(); } + + default Optional<FormMetaData> mapMetaData(XtaMessageMetaData value) { + return Optional.ofNullable(value); + } } diff --git a/xta-adapter/src/main/java/de/ozgcloud/eingang/xta/XtaMessageMetaData.java b/xta-adapter/src/main/java/de/ozgcloud/eingang/xta/XtaMessageMetaData.java index 66d4ed8d011521b3895e738a3eaf7d91b35af8fa..84fc3290bd1420e24750706a3a073cca4801ea2a 100644 --- a/xta-adapter/src/main/java/de/ozgcloud/eingang/xta/XtaMessageMetaData.java +++ b/xta-adapter/src/main/java/de/ozgcloud/eingang/xta/XtaMessageMetaData.java @@ -2,19 +2,58 @@ package de.ozgcloud.eingang.xta; import java.time.ZonedDateTime; +import de.ozgcloud.eingang.common.formdata.FormMetaData; +import de.ozgcloud.eingang.common.formdata.IncomingFile; import lombok.Builder; import lombok.Getter; +import lombok.ToString; @Builder @Getter -class XtaMessageMetaData { +@ToString +class XtaMessageMetaData implements FormMetaData { + static final String SERVICE = "service"; + static final String MESSAGE_TYPE_ENTRY_NAME = "messageType"; + static final String MESSAGE_TYPE_LIST_VERSION = "messageTypeListVersion"; + static final String MESSAGE_ID_ENTRY_NAME = "messageId"; + static final String XTA_IDENTIFIER_ENTRY_NAME = "xtaIdentifier"; + // MsgIdentification.MessageId private XtaMessageId messageId; + // DeliveryAttributes.origin private ZonedDateTime origin; // DeliveryAttributes.delivery private ZonedDateTime delivery; + // Qualifier.MessageType.code private String messageType; + // Qualifier.MessageType.listVersion + private String messageTypeListVersion; + // Qualifier.Service + private String service; + + private String xtaIdentifier; + + private IncomingFile metaDataFile; + + @Override + public String getEntry(String name) { + switch (name) { + case MESSAGE_TYPE_ENTRY_NAME: + return getMessageType(); + case MESSAGE_TYPE_LIST_VERSION: + return getMessageTypeListVersion(); + case MESSAGE_ID_ENTRY_NAME: + return getMessageId().toString(); + case XTA_IDENTIFIER_ENTRY_NAME: + return getXtaIdentifier(); + case SERVICE: + return getService(); + + default: + return null; + } + } } diff --git a/xta-adapter/src/main/java/de/ozgcloud/eingang/xta/XtaMessageMetaDataMapper.java b/xta-adapter/src/main/java/de/ozgcloud/eingang/xta/XtaMessageMetaDataMapper.java index 2cb772154e77246a41508a0116dd6db7f9cf9cae..f5566e157a78701db29b3ca828e1e9e8fdcb5cef 100644 --- a/xta-adapter/src/main/java/de/ozgcloud/eingang/xta/XtaMessageMetaDataMapper.java +++ b/xta-adapter/src/main/java/de/ozgcloud/eingang/xta/XtaMessageMetaDataMapper.java @@ -13,10 +13,14 @@ import eu.osci.ws._2014._10.transport.MessageMetaData; @Mapper interface XtaMessageMetaDataMapper { + @Mapping(target = "messageTypeListVersion", ignore = true) + @Mapping(target = "metaDataFile", ignore = true) + @Mapping(target = "service", ignore = true) @Mapping(target = "origin", source = "deliveryAttributes.origin") @Mapping(target = "delivery", source = "deliveryAttributes.delivery") @Mapping(target = "messageId", source = "msgIdentification.messageID.value") @Mapping(target = "messageType", source = "qualifier.messageType.code") + @Mapping(target = "xtaIdentifier", source = "destinations.reader.identifier.value") XtaMessageMetaData fromSoap(MessageMetaData metaData); default XtaMessageId fromString(String id) { diff --git a/xta-adapter/src/main/java/de/ozgcloud/eingang/xta/XtaRemoteService.java b/xta-adapter/src/main/java/de/ozgcloud/eingang/xta/XtaRemoteService.java index c1d3ecfb782a7e0f42f2feab9cadb78b621ff15c..a837c55d3c1670242f12ea891542be116052e09f 100644 --- a/xta-adapter/src/main/java/de/ozgcloud/eingang/xta/XtaRemoteService.java +++ b/xta-adapter/src/main/java/de/ozgcloud/eingang/xta/XtaRemoteService.java @@ -94,7 +94,6 @@ class XtaRemoteService { } MsgStatusListTypeAndHeaderResponse getGenericStatusList(Object request) { - var template = webServiceTemplateBuilder.setMarshaller(osciMarshaller).setUnmarshaller(osciMarshaller).build(); return template.sendAndReceive(buildMarshalCallBack(request, buildActionCallback()), buildHeaderExtractor()); @@ -183,10 +182,12 @@ class XtaRemoteService { public XtaMessage getMessage(XtaMessageId messageId) { var contentContainer = loadContentContainer(messageId.toString()); + XtaFile formDataFile = getMessage(contentContainer); return XtaMessage.builder() .metaData(null) - .messageFiles(Collections.singleton(getMessage(contentContainer))) + .primaryFormDataMessage(formDataFile.name()) + .messageFiles(Collections.singleton(formDataFile)) .attachments(getAttachments(contentContainer).toList()) .build(); } diff --git a/xta-adapter/src/main/java/de/ozgcloud/eingang/xta/XtaService.java b/xta-adapter/src/main/java/de/ozgcloud/eingang/xta/XtaService.java index d5a8d537c84074c7a8bd5849fd744b320eeb3820..500e78da873a6acfc55c01a880f4ec953a875d4a 100644 --- a/xta-adapter/src/main/java/de/ozgcloud/eingang/xta/XtaService.java +++ b/xta-adapter/src/main/java/de/ozgcloud/eingang/xta/XtaService.java @@ -4,6 +4,7 @@ import static java.util.Collections.*; import java.util.Collection; import java.util.List; +import java.util.Optional; import java.util.Spliterators; import java.util.stream.Stream; import java.util.stream.StreamSupport; @@ -15,6 +16,7 @@ import org.springframework.stereotype.Service; import de.ozgcloud.eingang.common.errorhandling.TechnicalException; import de.ozgcloud.eingang.common.formdata.FormData; +import de.ozgcloud.eingang.common.formdata.FormData.Representations; import de.ozgcloud.eingang.common.formdata.IncomingFile; import de.ozgcloud.eingang.common.formdata.IncomingFileGroup; import de.ozgcloud.eingang.common.vorgang.VorgangNummerSupplier; @@ -44,7 +46,10 @@ class XtaService { private XtaCurrentIdentifierService service; public Stream<FormData> getMessages() { - return createXtaMessageStream().filter(this::isSupportedMessageType).map(this::getFormData); + return createXtaMessageStream() + .filter(this::isSupportedMessageType) + .map(this::getFormDataIfNoRuntimeException) + .flatMap(Optional::stream); } Stream<XtaMessageMetaData> createXtaMessageStream() { @@ -66,13 +71,38 @@ class XtaService { return false; } - public FormData getFormData(@NonNull XtaMessageMetaData metaData) { + Optional<FormData> getFormDataIfNoRuntimeException(@NonNull XtaMessageMetaData metaData) { + try { + return Optional.of(getFormData(metaData)); + } catch (RuntimeException exception) { + LOG.error("Failed to process xta message (id: %s)".formatted(metaData.getMessageId()), exception); + return Optional.empty(); + } + } + + FormData getFormData(@NonNull XtaMessageMetaData metaData) { var msg = remoteService.getMessage(metaData.getMessageId()); var incomingFiles = xtaIncomingFilesMapper.toIncomingFiles(msg.getMessageFiles()); var representationsAttachmentsPair = getRepresentationsAttachmentsPair(metaData, incomingFiles); var formData = mapper.toFormData(representationsAttachmentsPair, metaData, vorgangNummerSupplier); - return addAttachments(msg, formData); + formData = addAttachments(msg, formData); + + return addRepresentations(formData, msg); + } + + FormData addRepresentations(FormData formData, XtaMessage msg) { + return formData.toBuilder().control( + formData.getControl().toBuilder() + .representations(Optional.of(buildRepresentations(formData.getControl().getRepresentations(), msg))) + .build()) + .build(); + } + + private Representations buildRepresentations(Optional<Representations> base, XtaMessage msg) { + return base.map(Representations::toBuilder).orElseGet(Representations::builder) + .primaryFormDataRepresentation(msg.getPrimaryFormDataMessage()) + .build(); } FormData addAttachments(XtaMessage msg, FormData inFormData) { diff --git a/xta-adapter/src/test/helm/xta_adapter_cronjob_env_test.yaml b/xta-adapter/src/test/helm/xta_adapter_cronjob_env_test.yaml index 77547800e84d3f8f60fe508c57df9e5f7d0a0de6..e247e20d6703fa518cf1eb74616e5447f4fd8a2e 100644 --- a/xta-adapter/src/test/helm/xta_adapter_cronjob_env_test.yaml +++ b/xta-adapter/src/test/helm/xta_adapter_cronjob_env_test.yaml @@ -107,7 +107,7 @@ tests: path: spec.jobTemplate.spec.template.spec.containers[0].env content: name: grpc_client_vorgang-manager-vorgang-manager_address - value: 'vorgang-manager.helm-test:9090' + value: 'dns:///vorgang-manager.helm-test:9090' - contains: path: spec.jobTemplate.spec.template.spec.containers[0].env content: @@ -152,7 +152,7 @@ tests: path: spec.jobTemplate.spec.template.spec.containers[0].env content: name: grpc_client_vorgang-manager-vorgang-manager_address - value: 'vorgang-manager.helm-test:9090' + value: 'dns:///vorgang-manager.helm-test:9090' - contains: path: spec.jobTemplate.spec.template.spec.containers[0].env content: diff --git a/xta-adapter/src/test/java/de/ozgcloud/eingang/xta/XtaIncomingFilesMapperTest.java b/xta-adapter/src/test/java/de/ozgcloud/eingang/xta/XtaIncomingFilesMapperTest.java index 1ae7d692986e14c57e983b2af836c8b637c33c92..8adbed4598d7224e121e0d723c6c29baf0456361 100644 --- a/xta-adapter/src/test/java/de/ozgcloud/eingang/xta/XtaIncomingFilesMapperTest.java +++ b/xta-adapter/src/test/java/de/ozgcloud/eingang/xta/XtaIncomingFilesMapperTest.java @@ -27,10 +27,8 @@ import static org.assertj.core.api.Assertions.*; import static org.mockito.Mockito.*; import java.util.List; -import java.util.UUID; import java.util.stream.Stream; -import de.ozgcloud.eingang.common.formdata.IncomingFileGroup; import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; import org.mockito.InjectMocks; @@ -49,8 +47,6 @@ class XtaIncomingFilesMapperTest { @Mock private ZipFileExtractor extractor; - private static final String ZIP_CONTENT_TYPE = "application/zip"; - @Nested class TestToIncomingFiles { @@ -59,12 +55,12 @@ class XtaIncomingFilesMapperTest { var xtaFile = XtaFileTestFactory.create(); var incomingFile = IncomingFileTestFactory.create(); when(mapper.toIncomingFile(xtaFile)).thenReturn(incomingFile); - when(mapper.extractZip(incomingFile)).thenAnswer(x -> Stream.of(incomingFile)); + when(mapper.tryToExtractZip(incomingFile)).thenAnswer(x -> Stream.of(incomingFile)); mapper.toIncomingFiles(List.of(xtaFile, xtaFile)); inOrder(mapper).verify(mapper, calls(2)).toIncomingFile(xtaFile); - inOrder(mapper).verify(mapper, calls(2)).extractZip(incomingFile); + inOrder(mapper).verify(mapper, calls(2)).tryToExtractZip(incomingFile); } @Test @@ -107,7 +103,7 @@ class XtaIncomingFilesMapperTest { } @Nested - class TestExtractZip { + class TestTryToExtractZip { @Mock IncomingFile outFile1; @@ -115,40 +111,29 @@ class XtaIncomingFilesMapperTest { @Mock IncomingFile outFile2; + private final IncomingFile zipFile = IncomingFileTestFactory.createBuilder() + .name("attachments.zip") + .build(); @Test void shouldExtractZipFiles() { var expectedExtractedFiles = List.of(outFile1, outFile2); - var zipFile = createTestIncomingFile(); when(extractor.extractIncomingFilesSafely(zipFile)).thenReturn(expectedExtractedFiles); - var extractedFiles = mapper.extractZip(zipFile).toList(); + var extractedFiles = mapper.tryToExtractZip(zipFile).toList(); assertThat(extractedFiles).isEqualTo(expectedExtractedFiles); } - IncomingFile createTestIncomingFile() { - return IncomingFileTestFactory.createBuilder() - .name("attachments.zip") - .contentType(ZIP_CONTENT_TYPE) - .build(); - } - @Test void shouldIgnoreNonZipFiles() { + when(extractor.extractIncomingFilesSafely(zipFile)).thenThrow(new RuntimeException()); var incomingFile = IncomingFileTestFactory.create(); - var extractedFiles = mapper.extractZip(incomingFile).toList(); + var extractedFiles = mapper.tryToExtractZip(incomingFile).toList(); assertThat(extractedFiles).containsExactly(incomingFile); } } - @Test - void testIsZipFilePredicate() { - assertThat(XtaIncomingFilesMapper.IS_ZIP_FILE.test(IncomingFileTestFactory.create())).isFalse(); - assertThat(XtaIncomingFilesMapper.IS_ZIP_FILE.test(IncomingFileTestFactory.createBuilder().contentType(ZIP_CONTENT_TYPE).build())) - .isTrue(); - } - } diff --git a/xta-adapter/src/test/java/de/ozgcloud/eingang/xta/XtaMessageMapperTest.java b/xta-adapter/src/test/java/de/ozgcloud/eingang/xta/XtaMessageMapperTest.java index 83d1dc8f4fee83ad384db085315e9fbcc37cd075..23a2f984e0b91d38e35e63c3d2d73efd8cd69733 100644 --- a/xta-adapter/src/test/java/de/ozgcloud/eingang/xta/XtaMessageMapperTest.java +++ b/xta-adapter/src/test/java/de/ozgcloud/eingang/xta/XtaMessageMapperTest.java @@ -13,6 +13,7 @@ import org.mockito.Mock; import org.mockito.Spy; import de.ozgcloud.eingang.common.formdata.FormData; +import de.ozgcloud.eingang.common.formdata.FormMetaDataTestFactory; import de.ozgcloud.eingang.common.vorgang.VorgangNummerSupplier; class XtaMessageMapperTest { @@ -86,6 +87,14 @@ class XtaMessageMapperTest { assertThat(formData.getHeader().getFormEngineName()).isEqualTo(FormHeaderTestFactory.XDOMEA_FORM_ENGINE_NAME); } + @Test + void shouldSetDesinationId() { + var formData = doMapping(); + + assertThat(formData.getControl().getMetaData()).isPresent().get() + .extracting(metaData -> metaData.getEntry(XtaMessageMetaData.XTA_IDENTIFIER_ENTRY_NAME)) + .isEqualTo(FormMetaDataTestFactory.XTA_IDENTIFIER); + } private FormData doMapping() { return mapper.toFormData(representationsAttachmentsPair, xtaMessageMetaData, vorgangNummerSupplier); @@ -95,7 +104,6 @@ class XtaMessageMapperTest { @Nested class TestToFimFormData { - private XtaMessageMetaData xtaMessageMetaData; private RepresentationsAttachmentsPair representationsAttachmentsPair; @@ -108,7 +116,7 @@ class XtaMessageMapperTest { @Test void shouldSetFormEngineName() { - var formData = mapper.toFormData(representationsAttachmentsPair, xtaMessageMetaData, vorgangNummerSupplier); + var formData = mapper.toFormData(representationsAttachmentsPair, xtaMessageMetaData, vorgangNummerSupplier); assertThat(formData.getHeader().getFormEngineName()).isEqualTo(FormHeaderTestFactory.FIM_FORM_ENGINE_NAME); } diff --git a/xta-adapter/src/test/java/de/ozgcloud/eingang/xta/XtaMessageMetaDataMapperTest.java b/xta-adapter/src/test/java/de/ozgcloud/eingang/xta/XtaMessageMetaDataMapperTest.java index 26f1ef8d1c76ea3a17eb9b6031c3df7d5d1e54d9..1233e71346ca304904f22fb36108bae6731bb3d1 100644 --- a/xta-adapter/src/test/java/de/ozgcloud/eingang/xta/XtaMessageMetaDataMapperTest.java +++ b/xta-adapter/src/test/java/de/ozgcloud/eingang/xta/XtaMessageMetaDataMapperTest.java @@ -2,8 +2,6 @@ package de.ozgcloud.eingang.xta; import static org.assertj.core.api.Assertions.*; -import java.math.BigInteger; - import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; @@ -21,7 +19,7 @@ class XtaMessageMetaDataMapperTest { @Test void shouldMap() { - var response = MsgStatusListTypeAndHeaderResponseTestFactory.createBuilder().build(); + var response = MsgStatusListTypeAndHeaderResponseTestFactory.create(); var result = mapper.msgStatusListFromSoap(response); @@ -31,7 +29,7 @@ class XtaMessageMetaDataMapperTest { @DisplayName("should set moreMessagesAvailable to false") @Test void shouldSetMoreMessagesAvailableToFalse() { - var response = MsgStatusListTypeAndHeaderResponseTestFactory.createBuilder().build(); + var response = MsgStatusListTypeAndHeaderResponseTestFactory.create(); var result = mapper.msgStatusListFromSoap(response); diff --git a/xta-adapter/src/test/java/de/ozgcloud/eingang/xta/XtaMessageMetaDataTestFactory.java b/xta-adapter/src/test/java/de/ozgcloud/eingang/xta/XtaMessageMetaDataTestFactory.java index fbe07498eb8d3435d1c739a268ace2273bc133ac..5ee03139664cf766ba09ac8adc3e95d59e2fc246 100644 --- a/xta-adapter/src/test/java/de/ozgcloud/eingang/xta/XtaMessageMetaDataTestFactory.java +++ b/xta-adapter/src/test/java/de/ozgcloud/eingang/xta/XtaMessageMetaDataTestFactory.java @@ -4,11 +4,15 @@ import static de.ozgcloud.eingang.xta.XtaMessageTestFactory.*; import java.time.ZonedDateTime; +import de.ozgcloud.eingang.common.formdata.FormMetaDataTestFactory; + class XtaMessageMetaDataTestFactory { static final String MESSAGE_TYPE = "Geschaeftsgang.Geschaeftsgang.0201"; static final String FIM_MESSAGE_TYPE = "fim.S17000652.17000652001004"; static final ZonedDateTime ORIGIN = ZonedDateTime.parse("2022-10-29T15:45:52.4942149+02:00"); + static final String SERVICE = "urn:fim:Versammlungsanzeige:1.4"; + static final String MESSAGE_TYPE_LIST_VERSION = "1.0"; static XtaMessageMetaData create() { return createBuilder().build(); @@ -18,7 +22,10 @@ class XtaMessageMetaDataTestFactory { return XtaMessageMetaData.builder() .messageId(MESSAGE_ID) .messageType(MESSAGE_TYPE) - .origin(ORIGIN); + .messageTypeListVersion(MESSAGE_TYPE_LIST_VERSION) + .origin(ORIGIN) + .xtaIdentifier(FormMetaDataTestFactory.XTA_IDENTIFIER) + .service(SERVICE); } static XtaMessageMetaData createFim() { @@ -26,9 +33,7 @@ class XtaMessageMetaDataTestFactory { } static XtaMessageMetaData.XtaMessageMetaDataBuilder createFimBuilder() { - return XtaMessageMetaData.builder() - .messageId(MESSAGE_ID) - .messageType(FIM_MESSAGE_TYPE) - .origin(ORIGIN); + return createBuilder() + .messageType(FIM_MESSAGE_TYPE); } } diff --git a/xta-adapter/src/test/java/de/ozgcloud/eingang/xta/XtaMessageTestFactory.java b/xta-adapter/src/test/java/de/ozgcloud/eingang/xta/XtaMessageTestFactory.java index 6c8597cc38fd795a311ad8d3a70e64a5c24c6347..1a1397db1e1bae3588ef81e7162f8c80308b2283 100644 --- a/xta-adapter/src/test/java/de/ozgcloud/eingang/xta/XtaMessageTestFactory.java +++ b/xta-adapter/src/test/java/de/ozgcloud/eingang/xta/XtaMessageTestFactory.java @@ -5,6 +5,7 @@ class XtaMessageTestFactory { static final XtaMessageId MESSAGE_ID = XtaMessageId.from("urn:de:xta:messageid:dataport_xta_210:81e40808-91c6-4765-aaf4-1aa62fec8be9"); static final XtaFile attachment = XtaFileTestFactory.create(); + static final String PRIMARY_FORM_DATA_MESSAGE = XtaFileTestFactory.NAME; static XtaMessage create() { return createBuilder().build(); @@ -14,6 +15,7 @@ class XtaMessageTestFactory { return XtaMessage.builder() .metaData(XtaMessageMetaDataTestFactory.create()) .messageFile(XtaFileTestFactory.create()) + .primaryFormDataMessage(XtaFileTestFactory.NAME) .attachment(attachment); } } diff --git a/xta-adapter/src/test/java/de/ozgcloud/eingang/xta/XtaRemoteServiceITCase.java b/xta-adapter/src/test/java/de/ozgcloud/eingang/xta/XtaRemoteServiceFunctionalCase.java similarity index 100% rename from xta-adapter/src/test/java/de/ozgcloud/eingang/xta/XtaRemoteServiceITCase.java rename to xta-adapter/src/test/java/de/ozgcloud/eingang/xta/XtaRemoteServiceFunctionalCase.java diff --git a/xta-adapter/src/test/java/de/ozgcloud/eingang/xta/XtaServiceTest.java b/xta-adapter/src/test/java/de/ozgcloud/eingang/xta/XtaServiceTest.java index 374d71632023fb10b42f1698b4b7c44d1e462445..effc877a5d5045273819eef3e441eb6893da1f02 100644 --- a/xta-adapter/src/test/java/de/ozgcloud/eingang/xta/XtaServiceTest.java +++ b/xta-adapter/src/test/java/de/ozgcloud/eingang/xta/XtaServiceTest.java @@ -6,6 +6,7 @@ import static org.mockito.ArgumentMatchers.*; import static org.mockito.Mockito.*; import java.util.List; +import java.util.Optional; import java.util.stream.Stream; import org.junit.jupiter.api.BeforeEach; @@ -20,6 +21,8 @@ import org.mockito.Spy; import de.ozgcloud.eingang.common.errorhandling.TechnicalException; import de.ozgcloud.eingang.common.formdata.FormData; +import de.ozgcloud.eingang.common.formdata.FormData.Representations; +import de.ozgcloud.eingang.common.formdata.FormDataControlTestFactory; import de.ozgcloud.eingang.common.formdata.IncomingFile; import de.ozgcloud.eingang.common.formdata.IncomingFileTestFactory; import de.ozgcloud.eingang.common.vorgang.VorgangNummerSupplier; @@ -49,52 +52,93 @@ class XtaServiceTest { @Mock private XtaCurrentIdentifierService currentIdentifierService; + @Mock + private FormData formData; + + @Mock + private FormData formData2; + @Nested class TestGetMessagesAsFormData { private final XtaMessageMetaData messageMetaData = XtaMessageMetaDataTestFactory.create(); private final XtaMessage message = XtaMessageTestFactory.create(); - @BeforeEach - void setup() { - doReturn(Stream.of(messageMetaData)).when(service).createXtaMessageStream(); - } + @DisplayName("with one message") + @Nested + class TestWithOneMessage { + @BeforeEach + void setup() { + doReturn(Stream.of(messageMetaData)).when(service).createXtaMessageStream(); + } - @Test - void shouldCallCreateStream() { - service.getMessages(); + @Test + void shouldCallCreateStream() { + service.getMessages(); - verify(service).createXtaMessageStream(); - } + verify(service).createXtaMessageStream(); + } - @Test - void shouldCallFilterByMessageType() { - setupMocks(); + @Test + void shouldCallFilterByMessageType() { + setupMocks(); - service.getMessages().toList(); + service.getMessages().toList(); - verify(service).isSupportedMessageType(messageMetaData); - } + verify(service).isSupportedMessageType(messageMetaData); + } - @Test - void shouldCallGetFormData() { - setupMocks(); - doReturn(true).when(service).isSupportedMessageType(messageMetaData); + @Test + void shouldCallGetFormDataIfNoRuntimeException() { + setupMocks(); + doReturn(true).when(service).isSupportedMessageType(messageMetaData); - service.getMessages().toList(); + service.getMessages().toList(); - verify(service).getFormData(messageMetaData); + verify(service).getFormData(messageMetaData); + } + + @Test + void shouldNotCallGetFormDataIfNoRuntimeException() { + doReturn(false).when(service).isSupportedMessageType(messageMetaData); + + service.getMessages().toList(); + + verify(service, never()).getFormDataIfNoRuntimeException(any()); + } } - @Test - void shouldNotCallGetFormData() { - doReturn(false).when(service).isSupportedMessageType(messageMetaData); + @DisplayName("with multiple messages") + @Nested + class TestWithMultipleMessages { + private final XtaMessageMetaData messageMetaData2 = XtaMessageMetaDataTestFactory.createBuilder() + .messageId(XtaMessageId.from("messageId2")) + .build(); + private final XtaMessageMetaData messageMetaData3 = XtaMessageMetaDataTestFactory.createBuilder() + .messageId(XtaMessageId.from("messageId3")) + .build(); + + @BeforeEach + void setup() { + doReturn(Stream.of(messageMetaData, messageMetaData2, messageMetaData3)).when(service).createXtaMessageStream(); + } + + @DisplayName("should return stream of messages") + @Test + void shouldReturnStreamOfMessages() { + doReturn(true).when(service).isSupportedMessageType(messageMetaData); + doReturn(false).when(service).isSupportedMessageType(messageMetaData3); + doReturn(true).when(service).isSupportedMessageType(messageMetaData2); + doReturn(Optional.of(formData)).when(service).getFormDataIfNoRuntimeException(messageMetaData); + doReturn(Optional.of(formData2)).when(service).getFormDataIfNoRuntimeException(messageMetaData2); - service.getMessages().toList(); + var result = service.getMessages().toList(); - verify(service, never()).getFormData(any()); + assertThat(result).containsExactly(formData, formData2); + } } + private void setupMocks() { var testFormData = FormDataTestFactory.create(); when(mapper.toFormData(any(), any(), eq(vorgangNummerSupplier))).thenReturn(testFormData); @@ -129,6 +173,53 @@ class XtaServiceTest { } } + @DisplayName("get form data if no runtime exception") + @Nested + class TestGetFormDataIfNoRuntimeException { + + @Mock + XtaMessageMetaData messageMetaData; + + @Mock + FormData formData; + + @DisplayName("should call get formdata") + @Test + void shouldCallGetFormdata() { + service.getFormDataIfNoRuntimeException(messageMetaData); + + verify(service).getFormData(messageMetaData); + } + + @DisplayName("with exception") + @Nested + class TestWithException { + @DisplayName("should return empty") + @Test + void shouldReturnEmpty() { + doThrow(new RuntimeException("test-error")).when(service).getFormData(any()); + + var result = service.getFormDataIfNoRuntimeException(messageMetaData); + + assertThat(result).isEmpty(); + } + } + + @DisplayName("without exception") + @Nested + class TestWithoutException { + @DisplayName("should return") + @Test + void shouldReturn() { + doReturn(formData).when(service).getFormData(any()); + + var result = service.getFormDataIfNoRuntimeException(messageMetaData); + + assertThat(result).contains(formData); + } + } + } + @Nested class TestGetFormData { @@ -192,7 +283,7 @@ class XtaServiceTest { @Test void shouldReturnMappedResult() { - doReturn(mappedFormData).when(service).addAttachments(any(), any()); + doReturn(mappedFormData).when(service).addRepresentations(any(), any()); var result = service.getFormData(messageMetaData); @@ -353,4 +444,28 @@ class XtaServiceTest { } } + @Nested + class TestAddRepresentations { + @Test + void shouldAddPrimaryRepresentation() { + var result = service.addRepresentations(FormDataTestFactory.create(), XtaMessageTestFactory.create()); + + assertThat(result.getControl().getRepresentations()).isPresent().get() + .extracting(Representations::getPrimaryFormDataRepresentation).isEqualTo(XtaMessageTestFactory.PRIMARY_FORM_DATA_MESSAGE); + } + + @Test + void shouldRespectExistingRepresentation() { + var formData = FormDataTestFactory.createBuilder().control(FormDataControlTestFactory.createBuilder() + .representations(Optional.of( + Representations.builder().primaryFormDataPdfRepresentation("PDF_FILE").build())) + .build()).build(); + + var result = service.addRepresentations(formData, XtaMessageTestFactory.create()); + + var baseAssert = assertThat(result.getControl().getRepresentations()).isPresent().get(); + baseAssert.extracting(Representations::getPrimaryFormDataRepresentation).isEqualTo(XtaMessageTestFactory.PRIMARY_FORM_DATA_MESSAGE); + baseAssert.extracting(Representations::getPrimaryFormDataPdfRepresentation).isEqualTo("PDF_FILE"); + } + } }