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 52dcddeaf62afa188e0716294bf84d615eb5c945..100eefcfe1c6629650fcaaca896ccdabc973a84c 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 @@ -53,6 +53,10 @@ public class FormDataTestFactory { public static final String VORGANG_ID = "vorgangId"; + public static final List<IncomingFileGroup> ATTACHMENTS = List.of(IncomingFileGroupTestFactory.create(), + IncomingFileGroupTestFactory.createBuilder().name(ATTACHMENT_GROUP_2).build()); + public static final List<IncomingFile> REPRESENTATIONS = List.of(IncomingFileTestFactory.create()); + public static FormData create() { return createBuilder().build(); } @@ -72,10 +76,9 @@ public class FormDataTestFactory { .numberOfAttachments(2) // TODO zweites Attachment aus der TestFactory entfernen und die entsprechenden // Tests anpassen - .attachments(List.of(IncomingFileGroupTestFactory.create(), - IncomingFileGroupTestFactory.createBuilder().name(ATTACHMENT_GROUP_2).build())) + .attachments(ATTACHMENTS) .numberOfRepresentations(1) - .representations(List.of(IncomingFileTestFactory.create())); + .representations(REPRESENTATIONS); } @SafeVarargs 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 84ea086db65f80050e41f253694a1c674f017285..86b2f8738e84035d602e577756f98ffaa41cfe21 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 @@ -2,14 +2,12 @@ package de.ozgcloud.eingang.fim; 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; import org.w3c.dom.Element; import org.w3c.dom.Node; -import org.w3c.dom.NodeList; import org.w3c.dom.Text; import de.ozgcloud.eingang.common.formdata.FormData; @@ -17,46 +15,61 @@ import lombok.extern.log4j.Log4j2; @Service @Log4j2 -class FimDataMapper implements TriFunction<Document, FimScheme, FormData, FormData.FormDataBuilder> { - - private static final String LABEL_KEY = "label"; - private static final String VALUE_KEY = "value"; - - @Override - public FormData.FormDataBuilder apply(final Document document, final FimScheme fimScheme, final FormData initialFormData) { - final FormData.FormDataBuilder formDataBuilder = FormData.builder(); - Map<String, Object> data = new LinkedHashMap<>(); - process(document.getDocumentElement(), fimScheme, data, 0); - formDataBuilder.formData(data); - formDataBuilder.attachments(initialFormData.getAttachments()); - formDataBuilder.representations(initialFormData.getRepresentations()); - return formDataBuilder; - } - - private void process(final Element element, final FimScheme fimScheme, final Map<String, Object> data, final int level) { - final NodeList childNodes = element.getChildNodes(); - - LOG.debug(">".repeat(level) + " " + element.getNodeName()); - - for(int i = 0; i < childNodes.getLength();i++) { - final Node child = childNodes.item(i); - if (!(child instanceof Element)) { - continue; - } - if (child.getChildNodes().getLength() == 1 && child.getChildNodes().item(0) instanceof Text textNode) { - insertValueIntoFormData(data, fimScheme.getFieldName(child.getNodeName()), child.getNodeName(), textNode.getTextContent()); - } else { - final Map<String, Object> childMap = new LinkedHashMap<>(); - insertValueIntoFormData(data, fimScheme.getFieldName(child.getNodeName()), child.getNodeName(), childMap); - process((Element) child, fimScheme, childMap, level + 1); - } - } - } - - private void insertValueIntoFormData(final Map<String, Object> data, final Optional<String> fieldName, final String nodeName, final Object obj) { - final String[] fieldNameParts = nodeName.split(":"); - final String fieldNameWithoutNamespace = fieldNameParts[fieldNameParts.length - 1]; - final Map<String, Object> labelMap = Map.of(LABEL_KEY, fieldName.orElse(fieldNameWithoutNamespace), VALUE_KEY, obj); - data.put(fieldNameWithoutNamespace, labelMap); - } +class FimDataMapper implements TriFunction<Document, FimScheme, FormData, FormData> { + + private static final String LABEL_KEY = "label"; + private static final String VALUE_KEY = "value"; + + @Override + public FormData apply(Document document, FimScheme fimScheme, FormData initialFormData) { + return FormData.builder() + .formData(extractDocumentData(document.getDocumentElement(), fimScheme)) + .attachments(initialFormData.getAttachments()) + .representations(initialFormData.getRepresentations()) + .build(); + } + + Map<String, Object> extractDocumentData(Element documentRoot, FimScheme fimScheme) { + var data = new LinkedHashMap<String, Object>(); + processNode(documentRoot, fimScheme, data, 0); + return data; + } + + void processNode(Node element, FimScheme fimScheme, Map<String, Object> data, int level) { + LOG.debug(">".repeat(level) + " " + element.getNodeName()); + + var childNodes = element.getChildNodes(); + for (int i = 0; i < childNodes.getLength(); i++) { + if (childNodes.item(i) instanceof Element childElement) { + processElement(childElement, fimScheme, data, level); + } + } + } + + void processElement(Element childElement, FimScheme fimScheme, Map<String, Object> data, int level) { + var fieldName = fimScheme.getFieldName(childElement.getNodeName()); + var fieldNameWithoutNamespace = getFieldNameWithoutNamespace(childElement.getNodeName()); + var label = fieldName.orElse(fieldNameWithoutNamespace); + + if (isTextNode(childElement)) { + data.put(fieldNameWithoutNamespace, buildFieldMap(label, childElement.getTextContent())); + } else { + var childMap = new LinkedHashMap<String, Object>(); + data.put(fieldNameWithoutNamespace, buildFieldMap(label, childMap)); + processNode(childElement, fimScheme, childMap, level + 1); + } + } + + private String getFieldNameWithoutNamespace(String nodeName) { + var fieldNameParts = nodeName.split(":"); + return fieldNameParts[fieldNameParts.length - 1]; + } + + private boolean isTextNode(Node child) { + return child.getChildNodes().getLength() == 1 && child.getChildNodes().item(0) instanceof Text; + } + + private Map<String, Object> buildFieldMap(String fieldName, Object obj) { + return Map.<String, Object>of(LABEL_KEY, fieldName, VALUE_KEY, obj); + } } diff --git a/fim-adapter/src/main/java/de/ozgcloud/eingang/fim/FimDataUtil.java b/fim-adapter/src/main/java/de/ozgcloud/eingang/fim/FimDataUtil.java index f21f185c5b6365174c2eb7ab2169b64f007e9b6e..ca6e3716e8bd54ab9676c7aed71205e0fd294bc1 100644 --- a/fim-adapter/src/main/java/de/ozgcloud/eingang/fim/FimDataUtil.java +++ b/fim-adapter/src/main/java/de/ozgcloud/eingang/fim/FimDataUtil.java @@ -1,35 +1,40 @@ package de.ozgcloud.eingang.fim; -import org.apache.commons.lang3.ArrayUtils; - import java.util.Map; import java.util.Optional; -public class FimDataUtil { +import org.apache.commons.lang3.ArrayUtils; + +import lombok.AccessLevel; +import lombok.NoArgsConstructor; + +@NoArgsConstructor(access = AccessLevel.PRIVATE) +class FimDataUtil { + + public static Map<String, Object> getSubmap(Map<String, Object> data, String... path) { + var current = data; + for (final String step : path) { + current = map(current, step); + } + return current; + } - public static Map<String, Object> getSubmap(final Map<String, Object> data, final String... path) { - Map<String, Object> current = data; - for (final String step : path) { - current = map(current, step); - } - return current; - } - public static Optional<String> getValue(final Map<String, Object> data, final String... path) { - Map<String, Object> current = getSubmap(data, ArrayUtils.subarray(path, 0, path.length - 1)); - if (current == null) { - return Optional.empty(); - } - return Optional.ofNullable((String)((Map<String, Object>) current.get(path[path.length - 1])).get("value")); - } + public static Optional<String> getValue(final Map<String, Object> data, String... path) { + var current = getSubmap(data, ArrayUtils.subarray(path, 0, path.length - 1)); + if (current == null) { + return Optional.empty(); + } + return Optional.ofNullable((String) ((Map<String, Object>) current.get(path[path.length - 1])).get("value")); + } - private static Map<String, Object> map(Map<String, Object> obj, String key) { - if (obj == null) { - return null; - } - final Object data = obj.get(key); - if (!(data instanceof Map)) { - return null; - } - return (Map<String, Object>)((Map<String, Object>) data).get("value"); - } + private static Map<String, Object> map(Map<String, Object> obj, String key) { + if (obj == null) { + return null; + } + var data = obj.get(key); + if (!(data instanceof Map)) { + return null; + } + return (Map<String, Object>) ((Map<String, Object>) data).get("value"); + } } 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 381cb4e04896e27ae780605187fc041ebdd943e0..adfaeaecd74b248202dce577ef437a71bd5038a7 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 @@ -24,8 +24,8 @@ import de.ozgcloud.eingang.common.formdata.FormHeader; import io.micrometer.common.util.StringUtils; import lombok.extern.log4j.Log4j2; -@Service @Log4j2 +@Service public class FimService { public static final String UNKNOWN_SCHEME_NAME = "unknown"; @@ -89,17 +89,16 @@ public class FimService { 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()); + var formData = fimDataMapper.apply(document, scheme, initialFormData); - extractAntragsteller(builder, initialFormData); - extractVorgangsname(builder, initialFormData); - - return builder.build(); + return formData.toBuilder() + .header(initialFormData.getHeader()) + .antragsteller(buildAntragsteller(formData)) + .header(buildFormHeader(formData)) + .build(); } - FimScheme getSchemeForIdentifier(final String fimSchemaName) { + FimScheme getSchemeForIdentifier(String fimSchemaName) { final FimSchemeIdentifier fimSchemeIdentifier = FimSchemeIdentifier.fromString(fimSchemaName); final FimScheme fimScheme = fimSchemeCatalogue.get(fimSchemeIdentifier); if (fimScheme == null) { @@ -109,12 +108,12 @@ public class FimService { 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"); + // THINKME In Mapper auslagern + private Antragsteller buildAntragsteller(FormData formData) { + var anzeigenErsteller = getAnzeigenErsteller(formData); + var anschrift = getAnschrift(anzeigenErsteller); - Antragsteller antragsteller = Antragsteller.builder() + return Antragsteller.builder() .vorname(FimDataUtil.getValue(anzeigenErsteller, "F60000228").orElse(null)) .nachname(FimDataUtil.getValue(anzeigenErsteller, "F60000227").orElse(null)) .email(FimDataUtil.getValue(anzeigenErsteller, "F60000242").orElse(null)) @@ -122,18 +121,25 @@ public class FimService { .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"); + // ASKME AnzeigenErsteller ?! + private Map<String, Object> getAnzeigenErsteller(FormData formData) { + return FimDataUtil.getSubmap(formData.getFormData(), "G17002112"); + } + + private Map<String, Object> getAnschrift(Map<String, Object> anzeigenErsteller) { + return FimDataUtil.getSubmap(anzeigenErsteller, "G60000086"); + } - final FormHeader.FormHeaderBuilder headerBuilder = current.getHeader().toBuilder(); + private FormHeader buildFormHeader(FormData formData) { + return formData.getHeader().toBuilder() + .formName(getVorgangsName(formData).orElse(null)) + .build(); + } - headerBuilder.formName(vorgangsname.orElse(null)); - builder.header(headerBuilder.build()); + private Optional<String> getVorgangsName(FormData formData) { + return FimDataUtil.getValue(formData.getFormData(), "G17003529", "G05001479", "G05001480", "F05002753"); } } \ No newline at end of file diff --git a/fim-adapter/src/test/java/de/ozgcloud/eingang/fim/FimDataMapperTest.java b/fim-adapter/src/test/java/de/ozgcloud/eingang/fim/FimDataMapperTest.java new file mode 100644 index 0000000000000000000000000000000000000000..3a53dd9665d2678c5f1dc49e87817453704240b3 --- /dev/null +++ b/fim-adapter/src/test/java/de/ozgcloud/eingang/fim/FimDataMapperTest.java @@ -0,0 +1,117 @@ +package de.ozgcloud.eingang.fim; + +import static org.assertj.core.api.Assertions.*; +import static org.mockito.ArgumentMatchers.*; +import static org.mockito.Mockito.*; + +import java.util.Map; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.Spy; +import org.w3c.dom.Document; +import org.w3c.dom.Element; + +import de.ozgcloud.eingang.common.formdata.FormData; +import de.ozgcloud.eingang.common.formdata.FormDataTestFactory; + +class FimDataMapperTest { + + @Spy + @InjectMocks + private FimDataMapper mapper; + + @DisplayName("Apply") + @Nested + class TestApply { + + @Mock + private Document document; + @Mock + private Element element; + @Mock + private FimScheme fimScheme; + @Mock + private Map<String, Object> extractedDocumentData; + + private final FormData formData = FormDataTestFactory.create(); + + @BeforeEach + void mock() { + when(document.getDocumentElement()).thenReturn(element); + + doReturn(extractedDocumentData).when(mapper).extractDocumentData(any(), any()); + } + + @Test + void shouldCallExtractDocumentData() { + apply(); + + verify(mapper).extractDocumentData(element, fimScheme); + } + + @Test + void shouldPutExtractDocumentDataInFormData() { + var appliedFormData = apply(); + + assertThat(appliedFormData.getFormData()).isEqualTo(extractedDocumentData); + } + + @Test + void shouldKeepAttachmentsInFormData() { + var appliedFormData = apply(); + + assertThat(appliedFormData.getAttachments()).isEqualTo(FormDataTestFactory.ATTACHMENTS); + } + + @Test + void shouldKeepRepresentationsInFormData() { + var appliedFormData = apply(); + + assertThat(appliedFormData.getRepresentations()).isEqualTo(FormDataTestFactory.REPRESENTATIONS); + } + + private FormData apply() { + return mapper.apply(document, fimScheme, formData); + } + } + + @DisplayName("Extract document data") + @Nested + class TestExtractDocumentData { + + @Mock + private Element root; + @Mock + private FimScheme fimScheme; + + @BeforeEach + void mock() { + doNothing().when(mapper).processNode(any(), any(), any(), anyInt()); + } + + @Test + void shouldCallProcessElement() { + mapper.extractDocumentData(root, fimScheme); + + verify(mapper).processNode(eq(root), eq(fimScheme), any(), eq(0)); + } + + @Test + void shouldReturnCreatedMap() { + var dataMap = mapper.extractDocumentData(root, fimScheme); + + assertThat(dataMap).isNotNull(); + } + } + + @DisplayName("Process element") + @Nested + class TestProcessElement { + + } +} \ No newline at end of file