diff --git a/common/src/main/java/de/ozgcloud/eingang/common/xml/XMLHelper.java b/common/src/main/java/de/ozgcloud/eingang/common/xml/XMLHelper.java new file mode 100644 index 0000000000000000000000000000000000000000..c94b0ae5cc80b81378f6013bb6601bca7835cd65 --- /dev/null +++ b/common/src/main/java/de/ozgcloud/eingang/common/xml/XMLHelper.java @@ -0,0 +1,64 @@ +package de.ozgcloud.eingang.common.xml; + +import java.io.IOException; + +import javax.xml.XMLConstants; +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.ParserConfigurationException; +import javax.xml.xpath.XPathExpression; +import javax.xml.xpath.XPathExpressionException; +import javax.xml.xpath.XPathFactory; +import javax.xml.xpath.XPathFactoryConfigurationException; + +import org.w3c.dom.Document; +import org.xml.sax.SAXException; + +import de.ozgcloud.eingang.common.errorhandling.TechnicalException; +import de.ozgcloud.eingang.common.formdata.IncomingFile; + +public class XMLHelper { + + private XMLHelper() { + } + + private static final DocumentBuilder DOCUMENT_BUILDER = createDocumentBuilder(); + + private static DocumentBuilder createDocumentBuilder() { + var documentBuilderFactory = DocumentBuilderFactory.newInstance(); + try { + documentBuilderFactory.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true); + return documentBuilderFactory.newDocumentBuilder(); + } catch (ParserConfigurationException e) { + throw new TechnicalException("Failed to configure document builder", e); + } + } + + private static final XPathFactory X_PATH_FACTORY = createXPathFactory(); + + private static XPathFactory createXPathFactory() { + var xPathFactory = XPathFactory.newInstance(); + try { + xPathFactory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, Boolean.TRUE); + return xPathFactory; + } catch (XPathFactoryConfigurationException e) { + throw new TechnicalException("Failed to configure xpath factory!", e); + } + } + + public static Document parseDocument(IncomingFile incomingFile) { + try (var inputStream = incomingFile.getContentStream()) { + return DOCUMENT_BUILDER.parse(inputStream); + } catch (SAXException | IOException e) { + throw new TechnicalException("Failed to parse xml document!", e); + } + } + + public static XPathExpression compileXPathExpression(String xPathString) { + try { + return X_PATH_FACTORY.newXPath().compile(xPathString); + } catch (XPathExpressionException e) { + throw new TechnicalException("Failed to compile xpath expression!", e); + } + } +} diff --git a/semantik-adapter/src/main/java/de/ozgcloud/eingang/semantik/common/ReadZipException.java b/common/src/main/java/de/ozgcloud/eingang/common/zip/ReadZipException.java similarity index 82% rename from semantik-adapter/src/main/java/de/ozgcloud/eingang/semantik/common/ReadZipException.java rename to common/src/main/java/de/ozgcloud/eingang/common/zip/ReadZipException.java index c3fcc85a910df48282884211d68617f4095248df..2a50bc6bc844a3d0a3f2aec157d1e93f1004f338 100644 --- a/semantik-adapter/src/main/java/de/ozgcloud/eingang/semantik/common/ReadZipException.java +++ b/common/src/main/java/de/ozgcloud/eingang/common/zip/ReadZipException.java @@ -1,4 +1,4 @@ -package de.ozgcloud.eingang.semantik.common; +package de.ozgcloud.eingang.common.zip; public class ReadZipException extends RuntimeException { diff --git a/semantik-adapter/src/main/java/de/ozgcloud/eingang/semantik/common/ZipAttachmentReader.java b/common/src/main/java/de/ozgcloud/eingang/common/zip/ZipAttachmentReader.java similarity index 99% rename from semantik-adapter/src/main/java/de/ozgcloud/eingang/semantik/common/ZipAttachmentReader.java rename to common/src/main/java/de/ozgcloud/eingang/common/zip/ZipAttachmentReader.java index 02b4e95012b0343aa44ebd79f6f0305135ad9234..8f060cb8fa68e7045e788920dc9d5e6364fed2c1 100644 --- a/semantik-adapter/src/main/java/de/ozgcloud/eingang/semantik/common/ZipAttachmentReader.java +++ b/common/src/main/java/de/ozgcloud/eingang/common/zip/ZipAttachmentReader.java @@ -21,7 +21,7 @@ * Die sprachspezifischen Genehmigungen und Beschränkungen * unter der Lizenz sind dem Lizenztext zu entnehmen. */ -package de.ozgcloud.eingang.semantik.common; +package de.ozgcloud.eingang.common.zip; import java.io.File; import java.io.FileInputStream; diff --git a/common/src/test/java/de/ozgcloud/eingang/common/formdata/IncomingFileTestFactory.java b/common/src/test/java/de/ozgcloud/eingang/common/formdata/IncomingFileTestFactory.java index 40e803fe1c1a89f4937d00453d574ebb09df7c67..b8f2a5b22249707ee116edde4751a442efe2acdd 100644 --- a/common/src/test/java/de/ozgcloud/eingang/common/formdata/IncomingFileTestFactory.java +++ b/common/src/test/java/de/ozgcloud/eingang/common/formdata/IncomingFileTestFactory.java @@ -65,4 +65,8 @@ public class IncomingFileTestFactory { public static MockMultipartFile asMultipartFile(String multipartName, IncomingFile file) { return new MockMultipartFile(multipartName, file.getName(), file.getContentType(), file.getContentStream().readAllBytes()); } + + public static IncomingFile createWithName(String name) { + return createBuilder().name(name).build(); + } } diff --git a/semantik-adapter/src/test/java/de/ozgcloud/eingang/semantik/common/ZipAttachmentReaderTest.java b/common/src/test/java/de/ozgcloud/eingang/common/zip/ZipAttachmentReaderTest.java similarity index 95% rename from semantik-adapter/src/test/java/de/ozgcloud/eingang/semantik/common/ZipAttachmentReaderTest.java rename to common/src/test/java/de/ozgcloud/eingang/common/zip/ZipAttachmentReaderTest.java index f6e1fa7e07c716a5b00a059ea8e46c1c35d16116..8cd2ad76c5b602b4b4e9096211afca5621c8569b 100644 --- a/semantik-adapter/src/test/java/de/ozgcloud/eingang/semantik/common/ZipAttachmentReaderTest.java +++ b/common/src/test/java/de/ozgcloud/eingang/common/zip/ZipAttachmentReaderTest.java @@ -21,7 +21,7 @@ * Die sprachspezifischen Genehmigungen und Beschränkungen * unter der Lizenz sind dem Lizenztext zu entnehmen. */ -package de.ozgcloud.eingang.semantik.common; +package de.ozgcloud.eingang.common.zip; import static org.assertj.core.api.Assertions.*; import static org.junit.jupiter.api.Assertions.*; @@ -47,8 +47,6 @@ import org.springframework.util.MimeTypeUtils; import de.ozgcloud.common.test.TestUtils; import de.ozgcloud.eingang.common.formdata.IncomingFile; -import de.ozgcloud.eingang.semantik.common.ReadZipException; -import de.ozgcloud.eingang.semantik.common.ZipAttachmentReader; import lombok.SneakyThrows; class ZipAttachmentReaderTest { @@ -96,7 +94,7 @@ class ZipAttachmentReaderTest { void shouldFailSilentByEncryptedZip() { var zipAttachment = createZipAttachment(ZIP_ENCRYPTED); - assertThrows(ReadZipException.class, () -> zipAttachment.readContent()); + assertThrows(ReadZipException.class, zipAttachment::readContent); } private static ZipAttachmentReader createZipAttachment(String fileName) { @@ -115,9 +113,9 @@ class ZipAttachmentReaderTest { private static Pair<String, Long> createContentPair(String fileName) { var size = switch (fileName) { - case content_file_0_name -> content_file_0_size; - case content_file_1_name -> content_file_1_size; - default -> getFileSize(fileName); + case content_file_0_name -> content_file_0_size; + case content_file_1_name -> content_file_1_size; + default -> getFileSize(fileName); }; return Pair.of(fileName, size); } @@ -189,7 +187,7 @@ class ZipAttachmentReaderTest { var zipAttachment = ZipAttachmentReader.from(invalidZip, "invalid"); - assertThrows(ReadZipException.class, () -> zipAttachment.readContent()); + assertThrows(ReadZipException.class, zipAttachment::readContent); } @Test diff --git a/semantik-adapter/src/test/resources/attachment-1file.zip b/common/src/test/resources/attachment-1file.zip similarity index 100% rename from semantik-adapter/src/test/resources/attachment-1file.zip rename to common/src/test/resources/attachment-1file.zip diff --git a/semantik-adapter/src/test/resources/attachment-2files.zip b/common/src/test/resources/attachment-2files.zip similarity index 100% rename from semantik-adapter/src/test/resources/attachment-2files.zip rename to common/src/test/resources/attachment-2files.zip diff --git a/semantik-adapter/src/test/resources/attachment-empty.zip b/common/src/test/resources/attachment-empty.zip similarity index 100% rename from semantik-adapter/src/test/resources/attachment-empty.zip rename to common/src/test/resources/attachment-empty.zip diff --git a/semantik-adapter/src/test/resources/attachment-encrypted.zip b/common/src/test/resources/attachment-encrypted.zip similarity index 100% rename from semantik-adapter/src/test/resources/attachment-encrypted.zip rename to common/src/test/resources/attachment-encrypted.zip diff --git a/semantik-adapter/src/test/resources/zip-file-0.txt b/common/src/test/resources/zip-file-0.txt similarity index 100% rename from semantik-adapter/src/test/resources/zip-file-0.txt rename to common/src/test/resources/zip-file-0.txt diff --git a/semantik-adapter/src/test/resources/zip-file-1.txt b/common/src/test/resources/zip-file-1.txt similarity index 100% rename from semantik-adapter/src/test/resources/zip-file-1.txt rename to common/src/test/resources/zip-file-1.txt diff --git a/semantik-adapter/src/test/resources/zipbombs/filewithmanyfiles.dat.zip b/common/src/test/resources/zipbombs/filewithmanyfiles.dat.zip similarity index 100% rename from semantik-adapter/src/test/resources/zipbombs/filewithmanyfiles.dat.zip rename to common/src/test/resources/zipbombs/filewithmanyfiles.dat.zip diff --git a/semantik-adapter/src/test/resources/zipbombs/filewithnulls.dat.zip b/common/src/test/resources/zipbombs/filewithnulls.dat.zip similarity index 100% rename from semantik-adapter/src/test/resources/zipbombs/filewithnulls.dat.zip rename to common/src/test/resources/zipbombs/filewithnulls.dat.zip diff --git a/intelliform-adapter/src/main/java/de/ozgcloud/eingang/intelliform/AttachmentsContentAdder.java b/intelliform-adapter/src/main/java/de/ozgcloud/eingang/intelliform/AttachmentsContentAdder.java deleted file mode 100644 index 9bf4387c8ed466c54cf64b09d9f800e7346b0d9f..0000000000000000000000000000000000000000 --- a/intelliform-adapter/src/main/java/de/ozgcloud/eingang/intelliform/AttachmentsContentAdder.java +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright (C) 2022 Das Land Schleswig-Holstein vertreten durch den - * Ministerpräsidenten des Landes Schleswig-Holstein - * Staatskanzlei - * Abteilung Digitalisierung und zentrales IT-Management der Landesregierung - * - * Lizenziert unter der EUPL, Version 1.2 oder - sobald - * diese von der Europäischen Kommission genehmigt wurden - - * Folgeversionen der EUPL ("Lizenz"); - * Sie dürfen dieses Werk ausschließlich gemäß - * dieser Lizenz nutzen. - * Eine Kopie der Lizenz finden Sie hier: - * - * https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 - * - * Sofern nicht durch anwendbare Rechtsvorschriften - * gefordert oder in schriftlicher Form vereinbart, wird - * die unter der Lizenz verbreitete Software "so wie sie - * ist", OHNE JEGLICHE GEWÄHRLEISTUNG ODER BEDINGUNGEN - - * ausdrücklich oder stillschweigend - verbreitet. - * Die sprachspezifischen Genehmigungen und Beschränkungen - * unter der Lizenz sind dem Lizenztext zu entnehmen. - */ -package de.ozgcloud.eingang.intelliform; - -import java.io.File; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; - -import org.springframework.stereotype.Component; - -import de.ozgcloud.eingang.common.formdata.IncomingFile; -import de.ozgcloud.eingang.common.formdata.IncomingFileGroup; - -@Component -public class AttachmentsContentAdder { - - public List<IncomingFileGroup> addContentToAttachments(List<IncomingFileGroup> formDataFileGroups, List<IncomingFile> depositRequestFiles) { - var fileGroups = new ArrayList<IncomingFileGroup>(formDataFileGroups.size()); - for (IncomingFileGroup fileGroup : formDataFileGroups) { - var files = fileGroup.getFiles().stream() - .map(file -> file.toBuilder().file(getContentStreamFromDepositRequest(file.getVendorId(), depositRequestFiles)).build()) - .toList(); - fileGroups.add(fileGroup.toBuilder().clearFiles().files(files).build()); - } - return Collections.unmodifiableList(fileGroups); - } - - private File getContentStreamFromDepositRequest(String attachmentVendorId, List<IncomingFile> depositRequestFiles) { - - return depositRequestFiles.stream() - .filter(depositFile -> depositFile.getVendorId().equals(attachmentVendorId)) - .map(IncomingFile::getFile) - .findFirst() - .orElseThrow(() -> new RuntimeException( - "DepositFiles does not contain content for attachment with vendorId: " + attachmentVendorId)); - } -} diff --git a/intelliform-adapter/src/main/java/de/ozgcloud/eingang/intelliform/CustomHeaderReader.java b/intelliform-adapter/src/main/java/de/ozgcloud/eingang/intelliform/CustomHeaderReader.java deleted file mode 100644 index dad25e9f009aa064cc79e5837ccf4687d0dcdc89..0000000000000000000000000000000000000000 --- a/intelliform-adapter/src/main/java/de/ozgcloud/eingang/intelliform/CustomHeaderReader.java +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Copyright (C) 2022 Das Land Schleswig-Holstein vertreten durch den - * Ministerpräsidenten des Landes Schleswig-Holstein - * Staatskanzlei - * Abteilung Digitalisierung und zentrales IT-Management der Landesregierung - * - * Lizenziert unter der EUPL, Version 1.2 oder - sobald - * diese von der Europäischen Kommission genehmigt wurden - - * Folgeversionen der EUPL ("Lizenz"); - * Sie dürfen dieses Werk ausschließlich gemäß - * dieser Lizenz nutzen. - * Eine Kopie der Lizenz finden Sie hier: - * - * https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 - * - * Sofern nicht durch anwendbare Rechtsvorschriften - * gefordert oder in schriftlicher Form vereinbart, wird - * die unter der Lizenz verbreitete Software "so wie sie - * ist", OHNE JEGLICHE GEWÄHRLEISTUNG ODER BEDINGUNGEN - - * ausdrücklich oder stillschweigend - verbreitet. - * Die sprachspezifischen Genehmigungen und Beschränkungen - * unter der Lizenz sind dem Lizenztext zu entnehmen. - */ -package de.ozgcloud.eingang.intelliform; - -import java.util.HashMap; -import java.util.Map; -import java.util.Optional; -import java.util.function.Consumer; - -import org.springframework.stereotype.Component; -import org.w3c.dom.Attr; -import org.w3c.dom.Document; - -@Component -public class CustomHeaderReader { - - public static final String HEADER_POSTFACH_ID = "u:saml_legacypostkorbhandle"; - public static final String HEADER_VORNAME = "u:saml_givenname"; - public static final String HEADER_NACHNAME = "u:saml_surname"; - public static final String HEADER_GEBURTSORT = "u:saml_placeofbirth"; - public static final String HEADER_GEBURTSNAME = "u:saml_birthname"; - public static final String HEADER_EMAIL = "u:saml_mail"; - public static final String HEADER_TELEFON = "u:saml_telephonenumber"; - public static final String HEADER_STRASSE = "u:saml_postaladdress"; - public static final String HEADER_PLZ = "u:saml_postalcode"; - public static final String HEADER_ORT = "u:saml_localityname"; - - public Map<String, Object> getHeader(Document document) { - var map = new HashMap<String, Object>(); - Consumer<Attr> addHeader = attr -> map.put(attr.getName(), attr.getValue()); - getAttribute(document, HEADER_POSTFACH_ID).ifPresent(addHeader); - getAttribute(document, HEADER_VORNAME).ifPresent(addHeader); - getAttribute(document, HEADER_NACHNAME).ifPresent(addHeader); - getAttribute(document, HEADER_GEBURTSNAME).ifPresent(addHeader); - getAttribute(document, HEADER_GEBURTSORT).ifPresent(addHeader); - getAttribute(document, HEADER_EMAIL).ifPresent(addHeader); - getAttribute(document, HEADER_TELEFON).ifPresent(addHeader); - getAttribute(document, HEADER_STRASSE).ifPresent(addHeader); - getAttribute(document, HEADER_PLZ).ifPresent(addHeader); - getAttribute(document, HEADER_ORT).ifPresent(addHeader); - return map; - } - - Optional<Attr> getAttribute(Document document, String name) { - return Optional.ofNullable(document.getDocumentElement().getAttributeNode(name)); - } -} \ No newline at end of file diff --git a/intelliform-adapter/src/main/java/de/ozgcloud/eingang/intelliform/DepositRequestIncomingFileMapper.java b/intelliform-adapter/src/main/java/de/ozgcloud/eingang/intelliform/DepositRequestIncomingFileMapper.java deleted file mode 100644 index db6bc571cea5ba0c9897dfef2bd7ded128ca9c35..0000000000000000000000000000000000000000 --- a/intelliform-adapter/src/main/java/de/ozgcloud/eingang/intelliform/DepositRequestIncomingFileMapper.java +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright (C) 2022 Das Land Schleswig-Holstein vertreten durch den - * Ministerpräsidenten des Landes Schleswig-Holstein - * Staatskanzlei - * Abteilung Digitalisierung und zentrales IT-Management der Landesregierung - * - * Lizenziert unter der EUPL, Version 1.2 oder - sobald - * diese von der Europäischen Kommission genehmigt wurden - - * Folgeversionen der EUPL ("Lizenz"); - * Sie dürfen dieses Werk ausschließlich gemäß - * dieser Lizenz nutzen. - * Eine Kopie der Lizenz finden Sie hier: - * - * https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 - * - * Sofern nicht durch anwendbare Rechtsvorschriften - * gefordert oder in schriftlicher Form vereinbart, wird - * die unter der Lizenz verbreitete Software "so wie sie - * ist", OHNE JEGLICHE GEWÄHRLEISTUNG ODER BEDINGUNGEN - - * ausdrücklich oder stillschweigend - verbreitet. - * Die sprachspezifischen Genehmigungen und Beschränkungen - * unter der Lizenz sind dem Lizenztext zu entnehmen. - */ -package de.ozgcloud.eingang.intelliform; - -import java.util.List; -import java.util.UUID; - -import org.springframework.stereotype.Component; - -import de.ozgcloud.common.binaryfile.TempFileUtils; -import de.ozgcloud.eingang.common.formdata.IncomingFile; - -@Component -class DepositRequestIncomingFileMapper { - - List<IncomingFile> mapFiles(Deposit depositData) { - return depositData.getData().getAttachments().stream() - .map(this::buildIncomingFile).toList(); - } - - private IncomingFile buildIncomingFile(Attachment attachment) { - var file = TempFileUtils.writeTmpFile(attachment.content); - - return IncomingFile.builder() - .id(UUID.randomUUID().toString()) - .vendorId(attachment.getId()) - .name(attachment.getName()) - .file(file) - .contentType(attachment.getContentType()) - .size(attachment.getContent().length) - .build(); - } -} diff --git a/intelliform-adapter/src/main/java/de/ozgcloud/eingang/intelliform/FormDataIncomingFileMapper.java b/intelliform-adapter/src/main/java/de/ozgcloud/eingang/intelliform/FormDataIncomingFileMapper.java deleted file mode 100644 index 6cd2ec7ceadb5a02f19ce3560858d3cb224d26eb..0000000000000000000000000000000000000000 --- a/intelliform-adapter/src/main/java/de/ozgcloud/eingang/intelliform/FormDataIncomingFileMapper.java +++ /dev/null @@ -1,84 +0,0 @@ -/* - * Copyright (C) 2022 Das Land Schleswig-Holstein vertreten durch den - * Ministerpräsidenten des Landes Schleswig-Holstein - * Staatskanzlei - * Abteilung Digitalisierung und zentrales IT-Management der Landesregierung - * - * Lizenziert unter der EUPL, Version 1.2 oder - sobald - * diese von der Europäischen Kommission genehmigt wurden - - * Folgeversionen der EUPL ("Lizenz"); - * Sie dürfen dieses Werk ausschließlich gemäß - * dieser Lizenz nutzen. - * Eine Kopie der Lizenz finden Sie hier: - * - * https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 - * - * Sofern nicht durch anwendbare Rechtsvorschriften - * gefordert oder in schriftlicher Form vereinbart, wird - * die unter der Lizenz verbreitete Software "so wie sie - * ist", OHNE JEGLICHE GEWÄHRLEISTUNG ODER BEDINGUNGEN - - * ausdrücklich oder stillschweigend - verbreitet. - * Die sprachspezifischen Genehmigungen und Beschränkungen - * unter der Lizenz sind dem Lizenztext zu entnehmen. - */ -package de.ozgcloud.eingang.intelliform; - -import java.util.ArrayList; -import java.util.List; -import java.util.UUID; - -import org.springframework.stereotype.Component; -import org.w3c.dom.Document; -import org.w3c.dom.Node; -import org.w3c.dom.NodeList; - -import de.ozgcloud.eingang.common.formdata.IncomingFile; -import de.ozgcloud.eingang.common.formdata.IncomingFileGroup; - -@Component -class FormDataIncomingFileMapper { - - int countAttachments(Document document) { - return document.getElementsByTagName("file").getLength(); - } - - List<IncomingFileGroup> mapAttachments(Document document) { - List<IncomingFileGroup> incomingFileGroups = new ArrayList<>(); - NodeList files = document.getElementsByTagName("file"); - - for (int idx = 0; idx < files.getLength(); idx++) { - String parentNodeName = buildParentNodeName(files.item(idx).getParentNode().getNodeName()); - IncomingFileGroup group = getIncomingFileGroup(incomingFileGroups, parentNodeName); - var updatedGroup = group.toBuilder().file(mapNodeToIncomingFile(files.item(idx))).build(); - incomingFileGroups.remove(group); - incomingFileGroups.add(updatedGroup); - } - - return incomingFileGroups; - } - - String buildParentNodeName(String parentNodeName) { - return parentNodeName.replaceAll("-item$", ""); - } - - private IncomingFile mapNodeToIncomingFile(Node item) { - return IncomingFile.builder() - .id(UUID.randomUUID().toString()) - .vendorId(item.getAttributes().getNamedItem("id").getNodeValue()) - .name(item.getFirstChild().getTextContent()) - .contentType(item.getAttributes().getNamedItem("content-type").getNodeValue()) - .size(Integer.valueOf(item.getAttributes().getNamedItem("length").getNodeValue())) - .build(); - } - - private IncomingFileGroup getIncomingFileGroup(List<IncomingFileGroup> incomingFileGroups, String parentNodeName) { - return incomingFileGroups.stream() - .filter(group -> group.getName().equals(parentNodeName)) - .findFirst() - .orElseGet(() -> { - IncomingFileGroup fileGroup = IncomingFileGroup.builder().name(parentNodeName).build(); - incomingFileGroups.add(fileGroup); - return fileGroup; - }); - } -} diff --git a/intelliform-adapter/src/main/java/de/ozgcloud/eingang/intelliform/FormDataEndpoint.java b/intelliform-adapter/src/main/java/de/ozgcloud/eingang/intelliform/IntelliFormEndpoint.java similarity index 92% rename from intelliform-adapter/src/main/java/de/ozgcloud/eingang/intelliform/FormDataEndpoint.java rename to intelliform-adapter/src/main/java/de/ozgcloud/eingang/intelliform/IntelliFormEndpoint.java index 85fba9a36193a7303b83c4dce077ed65dac682e7..c562cae01b6d903da745260d7e31f29c9b39fb63 100644 --- a/intelliform-adapter/src/main/java/de/ozgcloud/eingang/intelliform/FormDataEndpoint.java +++ b/intelliform-adapter/src/main/java/de/ozgcloud/eingang/intelliform/IntelliFormEndpoint.java @@ -37,11 +37,12 @@ import org.springframework.ws.server.endpoint.annotation.RequestPayload; import org.springframework.ws.server.endpoint.annotation.ResponsePayload; import de.ozgcloud.eingang.semantik.SemantikAdapter; +import lombok.RequiredArgsConstructor; import lombok.extern.log4j.Log4j2; @Endpoint @Log4j2 -public class FormDataEndpoint { +public class IntelliFormEndpoint { private static final String NAMESPACE_URI = "http://xmlns.cit.de/intelliform/2009/webservices/backend"; @@ -50,8 +51,9 @@ public class FormDataEndpoint { private static final QName _DepositResponse_QNAME = new QName(NAMESPACE_URI, "depositResponse"); private static final QName _PrefillResponse_QNAME = new QName(NAMESPACE_URI, "prefillResponse"); + @Autowired - private SemantikFormDataMapper semantikFormDataMapper; + private IntelliFormMapper intelliFormMapper; @Autowired private SemantikAdapter semantikAdapter; @@ -60,7 +62,8 @@ public class FormDataEndpoint { public JAXBElement<DepositResponse> inputFormData(@RequestPayload Deposit deposit) throws IOException, ParserConfigurationException { try { - semantikAdapter.processFormData(semantikFormDataMapper.mapToFormData(deposit)); + var formData = intelliFormMapper.mapToFormData(deposit.getData()); + semantikAdapter.processFormData(formData); } catch (Exception e) { LOG.error("Error processing form data", e); throw e; diff --git a/intelliform-adapter/src/main/java/de/ozgcloud/eingang/intelliform/IntelliFormMapper.java b/intelliform-adapter/src/main/java/de/ozgcloud/eingang/intelliform/IntelliFormMapper.java new file mode 100644 index 0000000000000000000000000000000000000000..b073dd971016dbdf7b7930efc27309a1682eb65c --- /dev/null +++ b/intelliform-adapter/src/main/java/de/ozgcloud/eingang/intelliform/IntelliFormMapper.java @@ -0,0 +1,124 @@ +/* + * Copyright (C) 2022 Das Land Schleswig-Holstein vertreten durch den + * Ministerpräsidenten des Landes Schleswig-Holstein + * Staatskanzlei + * Abteilung Digitalisierung und zentrales IT-Management der Landesregierung + * + * Lizenziert unter der EUPL, Version 1.2 oder - sobald + * diese von der Europäischen Kommission genehmigt wurden - + * Folgeversionen der EUPL ("Lizenz"); + * Sie dürfen dieses Werk ausschließlich gemäß + * dieser Lizenz nutzen. + * Eine Kopie der Lizenz finden Sie hier: + * + * https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 + * + * Sofern nicht durch anwendbare Rechtsvorschriften + * gefordert oder in schriftlicher Form vereinbart, wird + * die unter der Lizenz verbreitete Software "so wie sie + * ist", OHNE JEGLICHE GEWÄHRLEISTUNG ODER BEDINGUNGEN - + * ausdrücklich oder stillschweigend - verbreitet. + * Die sprachspezifischen Genehmigungen und Beschränkungen + * unter der Lizenz sind dem Lizenztext zu entnehmen. + */ +package de.ozgcloud.eingang.intelliform; + +import java.util.Collection; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.UUID; +import java.util.stream.Collectors; +import java.util.stream.IntStream; +import java.util.stream.Stream; + +import org.springframework.stereotype.Component; +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.NodeList; + +import de.ozgcloud.common.binaryfile.TempFileUtils; +import de.ozgcloud.eingang.common.errorhandling.TechnicalException; +import de.ozgcloud.eingang.common.formdata.FormData; +import de.ozgcloud.eingang.common.formdata.IncomingFile; +import de.ozgcloud.eingang.common.formdata.IncomingFileGroup; +import de.ozgcloud.eingang.common.xml.XMLHelper; +import lombok.RequiredArgsConstructor; + +@Component +@RequiredArgsConstructor +class IntelliFormMapper { + + public FormData mapToFormData(DepositData depositData) { + // Transform deposit data attachments to incoming files + Map<String, IncomingFile> incomingFileMap = depositData.getAttachments() + .stream() + .collect( + Collectors.toMap(Attachment::getId, this::mapAttachmentToIncomingFile) + ); + + // Parse the primary <myForm> xml representation + Document document = XMLHelper.parseDocument( + // Expect that the <primaryDataAttachmentId> refers to the XML file (and the <primaryFormAttachmentId> to the PDF file) + getIncomingFileById(depositData.getPrimaryDataAttachmentId(), incomingFileMap) + ); + + // Find ids of <file> attachments + var attachmentFileIds = findAttachmentIds(document); + var attachments = attachmentFileIds.stream() + .map(id -> getIncomingFileById(id, incomingFileMap)) + .map(this::createSingularFileGroup) + .toList(); + var representations = getNamesWithout(incomingFileMap.keySet(), attachmentFileIds).stream() + .map(id -> getIncomingFileById(id, incomingFileMap)) + .toList(); + return FormData.builder() + // Put each <file> attachment in a separate file group + .attachments(attachments) + .numberOfAttachments(attachments.size()) + // If a deposit attachment is not referenced by <file> it is interpreted as a representation + .representations(representations) + .numberOfRepresentations(representations.size()) + .build(); + } + + private IncomingFile getIncomingFileById(String id, Map<String, IncomingFile> incomingFileMap) { + if (!incomingFileMap.containsKey(id)) { + throw new TechnicalException("Failed to find deposit data attachment by id '%s'!".formatted(id)); + } + return incomingFileMap.get(id); + } + + private IncomingFileGroup createSingularFileGroup(IncomingFile incomingFile) { + return IncomingFileGroup.builder().file(incomingFile).build(); + } + + private List<String> getNamesWithout(Collection<String> names, Collection<String> excludedStrings) { + var excludedStringsSet = Set.copyOf(excludedStrings); + return names.stream().filter(name -> !excludedStringsSet.contains(name)).toList(); + } + + private List<String> findAttachmentIds(Document document) { + return streamElements(document.getElementsByTagName("file")) + .map(element -> element.getAttribute("id")) + .toList(); + } + + private Stream<Element> streamElements(NodeList nodeList) { + return IntStream.range(0, nodeList.getLength()) + .mapToObj(nodeList::item) + .map(Element.class::cast); + } + + IncomingFile mapAttachmentToIncomingFile(Attachment attachment) { + var file = TempFileUtils.writeTmpFile(attachment.content); + return IncomingFile.builder() + .id(UUID.randomUUID().toString()) + .vendorId(attachment.id) + .name(attachment.name) + .contentType(attachment.contentType) + .size(file.length()) + .file(file) + .build(); + } +} diff --git a/intelliform-adapter/src/main/java/de/ozgcloud/eingang/intelliform/RepresentationsCalculator.java b/intelliform-adapter/src/main/java/de/ozgcloud/eingang/intelliform/RepresentationsCalculator.java deleted file mode 100644 index 9018f33263566ab69c239614ca9d6f07aec81afc..0000000000000000000000000000000000000000 --- a/intelliform-adapter/src/main/java/de/ozgcloud/eingang/intelliform/RepresentationsCalculator.java +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright (C) 2022 Das Land Schleswig-Holstein vertreten durch den - * Ministerpräsidenten des Landes Schleswig-Holstein - * Staatskanzlei - * Abteilung Digitalisierung und zentrales IT-Management der Landesregierung - * - * Lizenziert unter der EUPL, Version 1.2 oder - sobald - * diese von der Europäischen Kommission genehmigt wurden - - * Folgeversionen der EUPL ("Lizenz"); - * Sie dürfen dieses Werk ausschließlich gemäß - * dieser Lizenz nutzen. - * Eine Kopie der Lizenz finden Sie hier: - * - * https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 - * - * Sofern nicht durch anwendbare Rechtsvorschriften - * gefordert oder in schriftlicher Form vereinbart, wird - * die unter der Lizenz verbreitete Software "so wie sie - * ist", OHNE JEGLICHE GEWÄHRLEISTUNG ODER BEDINGUNGEN - - * ausdrücklich oder stillschweigend - verbreitet. - * Die sprachspezifischen Genehmigungen und Beschränkungen - * unter der Lizenz sind dem Lizenztext zu entnehmen. - */ -package de.ozgcloud.eingang.intelliform; - -import java.util.List; -import java.util.stream.Collectors; - -import org.springframework.stereotype.Component; - -import de.ozgcloud.eingang.common.formdata.IncomingFile; -import de.ozgcloud.eingang.common.formdata.IncomingFileGroup; - -@Component -public class RepresentationsCalculator { - - List<IncomingFile> calculateRepresentations(List<IncomingFileGroup> formDataFileGroups, List<IncomingFile> depositRequestFiles) { - - return depositRequestFiles.stream() - .filter(file -> !formDataContainsFile(formDataFileGroups, file)) - .collect(Collectors.toList()); - } - - private boolean formDataContainsFile(List<IncomingFileGroup> formDataFileGroups, IncomingFile depositDataFile) { - - return formDataFileGroups.stream() - .anyMatch(fileGroup -> fileGroup.getFiles().stream() - .anyMatch(file -> file.getVendorId().equals(depositDataFile.getVendorId()))); - } -} diff --git a/intelliform-adapter/src/main/java/de/ozgcloud/eingang/intelliform/SemantikFormDataMapper.java b/intelliform-adapter/src/main/java/de/ozgcloud/eingang/intelliform/SemantikFormDataMapper.java deleted file mode 100644 index f4796328f0f9469c17291a9f4dfda6655c1213cf..0000000000000000000000000000000000000000 --- a/intelliform-adapter/src/main/java/de/ozgcloud/eingang/intelliform/SemantikFormDataMapper.java +++ /dev/null @@ -1,165 +0,0 @@ -/* - * Copyright (C) 2022 Das Land Schleswig-Holstein vertreten durch den - * Ministerpräsidenten des Landes Schleswig-Holstein - * Staatskanzlei - * Abteilung Digitalisierung und zentrales IT-Management der Landesregierung - * - * Lizenziert unter der EUPL, Version 1.2 oder - sobald - * diese von der Europäischen Kommission genehmigt wurden - - * Folgeversionen der EUPL ("Lizenz"); - * Sie dürfen dieses Werk ausschließlich gemäß - * dieser Lizenz nutzen. - * Eine Kopie der Lizenz finden Sie hier: - * - * https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 - * - * Sofern nicht durch anwendbare Rechtsvorschriften - * gefordert oder in schriftlicher Form vereinbart, wird - * die unter der Lizenz verbreitete Software "so wie sie - * ist", OHNE JEGLICHE GEWÄHRLEISTUNG ODER BEDINGUNGEN - - * ausdrücklich oder stillschweigend - verbreitet. - * Die sprachspezifischen Genehmigungen und Beschränkungen - * unter der Lizenz sind dem Lizenztext zu entnehmen. - */ -package de.ozgcloud.eingang.intelliform; - -import java.io.ByteArrayInputStream; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.Optional; - -import org.apache.commons.lang3.StringUtils; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Component; -import org.w3c.dom.Document; - -import de.ozgcloud.eingang.common.formdata.FormData; -import de.ozgcloud.eingang.common.formdata.IncomingFile; -import de.ozgcloud.eingang.common.formdata.IncomingFileGroup; -import de.ozgcloud.eingang.semantik.enginebased.FilesMapperHelper; -import lombok.RequiredArgsConstructor; - -//TODO Naming prüfen - er scheint mir nicht semantik zu mappen und befindet sich auch nicht im entsprechenden Modul -@Component -@RequiredArgsConstructor -class SemantikFormDataMapper { - static final String FILE = "file"; - - static final String CONTENT_FORMDATA_FILENAME_SUFFIX = "-Daten.xml"; - - static final String ATTACHMENTS_FIELD = "depositAttachments"; - - static final String ATTACHMENT_ID = "id"; - static final String ATTACHMENT_NAME = "name"; - static final String ATTACHMENT_DESCRIPTION = "description"; - static final String ATTACHMENT_ATTRIBUTES = "attributes"; - static final String ATTACHMENT_CONTENT = "content"; - static final String ATTACHMENT_CONTENT_TYPE = "contentType"; - - static final String HEADER_FIELD = "header"; - - static final String HEADER_ID = "t:id"; - static final String HEADER_TIMESTAMP = "t:timestamp"; - static final String HEADER_FORM_ID = "t:form-id"; - static final String HEADER_FORM = "t:form"; - static final String HEADER_SENDER = "t:sender"; - static final String HEADER_CUSTOMER = "t:customer"; - static final String HEADER_CUSTOMER_ID = "t:customer-id"; - static final String HEADER_CLIENT = "t:client"; - static final String HEADER_CLIENT_ID = "t:client-id"; - - @Autowired - private final XmlToJavaMapsMapper xmlToJavaMapsMapper; - - @Autowired - private final FormDataIncomingFileMapper formDataIncomingFileMapper; - - @Autowired - private final RepresentationsCalculator incomingFilesService; - - @Autowired - private final DepositRequestIncomingFileMapper depositRequestFilesMapper; - - @Autowired - private final AttachmentsContentAdder attachmentsContentAdder; - - @Autowired - private final CustomHeaderReader customHeaderReader; - - public FormData mapToFormData(Deposit depositData) { - var xmlFormDataStream = getXmlFormData(depositData.getData()); - - var document = xmlToJavaMapsMapper.parseAsW3cDocument(new ByteArrayInputStream(xmlFormDataStream)); - var formDataMap = xmlToJavaMapsMapper.mapXmlToJavaMaps(document); - - addFiles(document, depositRequestFilesMapper.mapFiles(depositData), formDataMap); - - addHeader(document, formDataMap); - - return FormData.builder().formData(Collections.unmodifiableMap(formDataMap)).build(); - } - - private byte[] getXmlFormData(DepositData depositData) { - var primaryId = depositData.getPrimaryDataAttachmentId(); - - return depositData.getAttachments().stream() - .filter(attachment -> StringUtils.equals(attachment.getId(), primaryId)) - .map(Attachment::getContent) - .findFirst() - .orElseThrow(() -> new RuntimeException("Request does not contain primary data attachment")); - } - - private void addFiles(Document document, List<IncomingFile> depositRequestFiles, Map<String, Object> formDataMap) { - List<IncomingFileGroup> attachments = formDataIncomingFileMapper.mapAttachments(document); - attachments = attachmentsContentAdder.addContentToAttachments(attachments, depositRequestFiles); - - List<IncomingFile> representations = incomingFilesService.calculateRepresentations(attachments, depositRequestFiles); - - formDataMap.put(FilesMapperHelper.FIELD_NAME_MAPPED_FILES, Map.of( - FilesMapperHelper.ATTACHMENTS, attachments, - FilesMapperHelper.REPRESENTATIONS, representations)); - - removeMappedFileReferences(attachments, formDataMap); - } - - void removeMappedFileReferences(List<IncomingFileGroup> attachments, Map<String, Object> formDataMap) { - attachments.forEach(group -> group.getFiles().stream().map(inFile -> getReferenceName(inFile.getVendorId(), formDataMap)).toList().stream() - .forEach(ref -> ref.ifPresent(entry -> formDataMap.remove(entry.getKey())))); - } - - @SuppressWarnings("unchecked") - Optional<Map.Entry<String, Object>> getReferenceName(String vendorId, Map<String, Object> formDataMap) { - return formDataMap.entrySet().stream().filter(entry -> { - Object file = null; - - if (entry.getValue() instanceof Map) { - file = ((Map<String, Object>) entry.getValue()).get(FILE); - } - - return Objects.nonNull(file) && ((Map<String, String>) file).containsValue(vendorId); - - }).findFirst(); - } - - private void addHeader(Document document, Map<String, Object> formData) { - formData.put(HEADER_FIELD, createHeaderMap(document)); - } - - private Map<String, Object> createHeaderMap(Document document) { - var map = new HashMap<String, Object>(); - map.put(HEADER_ID, document.getDocumentElement().getAttribute(HEADER_ID)); - map.put(HEADER_TIMESTAMP, document.getDocumentElement().getAttribute(HEADER_TIMESTAMP)); - map.put(HEADER_FORM_ID, document.getDocumentElement().getAttribute(HEADER_FORM_ID)); - map.put(HEADER_FORM, document.getDocumentElement().getAttribute(HEADER_FORM)); - map.put(HEADER_SENDER, document.getDocumentElement().getAttribute(HEADER_SENDER)); - map.put(HEADER_CUSTOMER, document.getDocumentElement().getAttribute(HEADER_CUSTOMER)); - map.put(HEADER_CUSTOMER_ID, document.getDocumentElement().getAttribute(HEADER_CUSTOMER_ID)); - map.put(HEADER_CLIENT, document.getDocumentElement().getAttribute(HEADER_CLIENT)); - map.put(HEADER_CLIENT_ID, document.getDocumentElement().getAttribute(HEADER_CLIENT_ID)); - map.putAll(customHeaderReader.getHeader(document)); - return map; - } -} \ No newline at end of file diff --git a/intelliform-adapter/src/test/java/de/ozgcloud/eingang/intelliform/AttachmentTestFactory.java b/intelliform-adapter/src/test/java/de/ozgcloud/eingang/intelliform/AttachmentTestFactory.java index 36b48dced9adf7c3c8c3189870f241870a44bdbf..940be0ebe3f5f6ad073ead1ac34756c8bd27b4e4 100644 --- a/intelliform-adapter/src/test/java/de/ozgcloud/eingang/intelliform/AttachmentTestFactory.java +++ b/intelliform-adapter/src/test/java/de/ozgcloud/eingang/intelliform/AttachmentTestFactory.java @@ -38,9 +38,13 @@ public class AttachmentTestFactory { t:form-id="waffen/kleinerWaffenschein" t:customer="Einheitlicher Ansprechpartner" t:customer-id="ea-sh" t:client="Schleswig-Holstein" - t:client-id="land"></myForm>"""; + t:client-id="land"> + <Upload1> + <file content-type="image/png" description="" id="VendorId3333" length="155251">Image.png</file> + </Upload1> + </myForm>"""; public static final byte[] XML_CONTENT = XML_CONTENT_STRING.getBytes(); - public static final String XML_ID = "myForm-xml"; + public static final String XML_ATTACHMENT_ID = "myForm-xml"; public static final String XML_NAME = "XML-Daten.xml"; public static final String PDF_ATTACHMENT_CONTENT_TYPE = "application/pdf"; @@ -48,6 +52,11 @@ public class AttachmentTestFactory { public static final String PDF_ATTACHMENT_NAME = "Scan1.pdf"; public static final String PDF_ATTACHMENT_ID = "VendorId2222"; + public static final String PNG_ATTACHMENT_CONTENT_TYPE = "application/pdf"; + public static final byte[] PNG_ATTACHMENT_CONTENT = "TestContent3".getBytes(); + public static final String PNG_ATTACHMENT_NAME = "Image.png"; + public static final String PNG_ATTACHMENT_ID = "VendorId3333"; + public static final String ATTRIBUTES_ENTRY_KEY = "X-IntelliForm-Signed"; public static final String ATTRIBUTES_ENTRY_VALUE = "false"; @@ -55,7 +64,7 @@ public class AttachmentTestFactory { var attachment = new Attachment(); attachment.getAttributes().add(createAttributesEntry()); attachment.setContentType(XML_CONTENT_TYPE); - attachment.setId(XML_ID); + attachment.setId(XML_ATTACHMENT_ID); attachment.setName(XML_NAME); attachment.setContent(XML_CONTENT); return attachment; @@ -71,10 +80,20 @@ public class AttachmentTestFactory { return attachment; } + public static Attachment createPng() { + var attachment = new Attachment(); + attachment.getAttributes().add(createAttributesEntry()); + attachment.setContent(PNG_ATTACHMENT_CONTENT); + attachment.setContentType(PNG_ATTACHMENT_CONTENT_TYPE); + attachment.setId(PNG_ATTACHMENT_ID); + attachment.setName(PNG_ATTACHMENT_NAME); + return attachment; + } + private static Entry createAttributesEntry() { var attributesEntry = new Entry(); attributesEntry.setKey(ATTRIBUTES_ENTRY_KEY); attributesEntry.setValue(ATTRIBUTES_ENTRY_VALUE); return attributesEntry; } -} \ No newline at end of file +} diff --git a/intelliform-adapter/src/test/java/de/ozgcloud/eingang/intelliform/AttachmentsContentAdderTest.java b/intelliform-adapter/src/test/java/de/ozgcloud/eingang/intelliform/AttachmentsContentAdderTest.java deleted file mode 100644 index eb1f646706f25d8a2f7861e39092522f4ec8b578..0000000000000000000000000000000000000000 --- a/intelliform-adapter/src/test/java/de/ozgcloud/eingang/intelliform/AttachmentsContentAdderTest.java +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Copyright (C) 2022 Das Land Schleswig-Holstein vertreten durch den - * Ministerpräsidenten des Landes Schleswig-Holstein - * Staatskanzlei - * Abteilung Digitalisierung und zentrales IT-Management der Landesregierung - * - * Lizenziert unter der EUPL, Version 1.2 oder - sobald - * diese von der Europäischen Kommission genehmigt wurden - - * Folgeversionen der EUPL ("Lizenz"); - * Sie dürfen dieses Werk ausschließlich gemäß - * dieser Lizenz nutzen. - * Eine Kopie der Lizenz finden Sie hier: - * - * https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 - * - * Sofern nicht durch anwendbare Rechtsvorschriften - * gefordert oder in schriftlicher Form vereinbart, wird - * die unter der Lizenz verbreitete Software "so wie sie - * ist", OHNE JEGLICHE GEWÄHRLEISTUNG ODER BEDINGUNGEN - - * ausdrücklich oder stillschweigend - verbreitet. - * Die sprachspezifischen Genehmigungen und Beschränkungen - * unter der Lizenz sind dem Lizenztext zu entnehmen. - */ -package de.ozgcloud.eingang.intelliform; - -import static org.assertj.core.api.Assertions.*; - -import java.util.List; - -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; - -import de.ozgcloud.eingang.common.formdata.IncomingFile; -import de.ozgcloud.eingang.common.formdata.IncomingFileGroup; -import de.ozgcloud.eingang.common.formdata.IncomingFileGroupTestFactory; -import de.ozgcloud.eingang.common.formdata.IncomingFileTestFactory; -import lombok.SneakyThrows; - -class AttachmentsContentAdderTest { - - AttachmentsContentAdder service; - - private List<IncomingFileGroup> attachments; - - private List<IncomingFile> depositRequestFiles; - - @BeforeEach - void init() { - - service = new AttachmentsContentAdder(); - - attachments = List.of(IncomingFileGroupTestFactory.createBuilder().clearFiles() - .files(List.of(IncomingFileTestFactory.createBuilder().file(null).build())).build()); - - depositRequestFiles = List.of(IncomingFileTestFactory.create()); - } - - @SneakyThrows - @Test - void testAddContentToAttachments() { - List<IncomingFileGroup> attachmentsWithContent = service.addContentToAttachments(attachments, depositRequestFiles); - - assertThat(attachmentsWithContent.get(0).getFiles().get(0).getContentStream()).hasBinaryContent(IncomingFileTestFactory.CONTENT); - } -} diff --git a/intelliform-adapter/src/test/java/de/ozgcloud/eingang/intelliform/CustomHeaderReaderTest.java b/intelliform-adapter/src/test/java/de/ozgcloud/eingang/intelliform/CustomHeaderReaderTest.java deleted file mode 100644 index eb435c85ecd0d0dc5214f7a595abc7bd9632f396..0000000000000000000000000000000000000000 --- a/intelliform-adapter/src/test/java/de/ozgcloud/eingang/intelliform/CustomHeaderReaderTest.java +++ /dev/null @@ -1,171 +0,0 @@ -/* - * Copyright (C) 2022 Das Land Schleswig-Holstein vertreten durch den - * Ministerpräsidenten des Landes Schleswig-Holstein - * Staatskanzlei - * Abteilung Digitalisierung und zentrales IT-Management der Landesregierung - * - * Lizenziert unter der EUPL, Version 1.2 oder - sobald - * diese von der Europäischen Kommission genehmigt wurden - - * Folgeversionen der EUPL ("Lizenz"); - * Sie dürfen dieses Werk ausschließlich gemäß - * dieser Lizenz nutzen. - * Eine Kopie der Lizenz finden Sie hier: - * - * https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 - * - * Sofern nicht durch anwendbare Rechtsvorschriften - * gefordert oder in schriftlicher Form vereinbart, wird - * die unter der Lizenz verbreitete Software "so wie sie - * ist", OHNE JEGLICHE GEWÄHRLEISTUNG ODER BEDINGUNGEN - - * ausdrücklich oder stillschweigend - verbreitet. - * Die sprachspezifischen Genehmigungen und Beschränkungen - * unter der Lizenz sind dem Lizenztext zu entnehmen. - */ -package de.ozgcloud.eingang.intelliform; - -import static org.assertj.core.api.Assertions.*; -import static org.mockito.Mockito.*; - -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Nested; -import org.junit.jupiter.api.Test; -import org.mockito.InjectMocks; -import org.mockito.Mock; -import org.w3c.dom.Attr; -import org.w3c.dom.Document; -import org.w3c.dom.Element; - -class CustomHeaderReaderTest { - - @InjectMocks - private CustomHeaderReader reader; - - @Mock - private Document document; - @Mock - private Element element; - @Mock - private Attr attribute; - - @BeforeEach - void setup() { - when(document.getDocumentElement()).thenReturn(element); - } - - @Test - void shouldNotAddIfNotPresent() { - var formData = reader.getHeader(document); - - assertThat(formData).isEmpty(); - } - - @Nested - class TestHeaderAdded { - - @BeforeEach - void setup() { - when(element.getAttributeNode(any())).thenReturn(attribute); - } - - @Test - void shouldAddPostfachId() { - when(attribute.getName()).thenReturn(CustomHeaderReader.HEADER_POSTFACH_ID); - when(attribute.getValue()).thenReturn(CustomHeaderTestFactory.POSTFACH_ID); - - var formData = reader.getHeader(document); - - assertThat(formData).containsEntry(CustomHeaderReader.HEADER_POSTFACH_ID, CustomHeaderTestFactory.POSTFACH_ID); - } - - @Test - void shouldAddVorname() { - when(attribute.getName()).thenReturn(CustomHeaderReader.HEADER_VORNAME); - when(attribute.getValue()).thenReturn(CustomHeaderTestFactory.VORNAME); - - var formData = reader.getHeader(document); - - assertThat(formData).containsEntry(CustomHeaderReader.HEADER_VORNAME, CustomHeaderTestFactory.VORNAME); - } - - @Test - void shouldAddNachname() { - when(attribute.getName()).thenReturn(CustomHeaderReader.HEADER_NACHNAME); - when(attribute.getValue()).thenReturn(CustomHeaderTestFactory.NACHNAME); - - var formData = reader.getHeader(document); - - assertThat(formData).containsEntry(CustomHeaderReader.HEADER_NACHNAME, CustomHeaderTestFactory.NACHNAME); - } - - @Test - void shouldAddGeburtsname() { - when(attribute.getName()).thenReturn(CustomHeaderReader.HEADER_GEBURTSNAME); - when(attribute.getValue()).thenReturn(CustomHeaderTestFactory.GEBURTSNAME); - - var formData = reader.getHeader(document); - - assertThat(formData).containsEntry(CustomHeaderReader.HEADER_GEBURTSNAME, CustomHeaderTestFactory.GEBURTSNAME); - } - - @Test - void shouldAddGeburtsort() { - when(attribute.getName()).thenReturn(CustomHeaderReader.HEADER_GEBURTSORT); - when(attribute.getValue()).thenReturn(CustomHeaderTestFactory.GEBURTSORT); - - var formData = reader.getHeader(document); - - assertThat(formData).containsEntry(CustomHeaderReader.HEADER_GEBURTSORT, CustomHeaderTestFactory.GEBURTSORT); - } - - @Test - void shouldAddEmail() { - when(attribute.getName()).thenReturn(CustomHeaderReader.HEADER_EMAIL); - when(attribute.getValue()).thenReturn(CustomHeaderTestFactory.EMAIL); - - var formData = reader.getHeader(document); - - assertThat(formData).containsEntry(CustomHeaderReader.HEADER_EMAIL, CustomHeaderTestFactory.EMAIL); - } - - @Test - void shouldAddTelefon() { - when(attribute.getName()).thenReturn(CustomHeaderReader.HEADER_TELEFON); - when(attribute.getValue()).thenReturn(CustomHeaderTestFactory.TELEFON); - - var formData = reader.getHeader(document); - - assertThat(formData).containsEntry(CustomHeaderReader.HEADER_TELEFON, CustomHeaderTestFactory.TELEFON); - } - - @Test - void shouldAddStrasse() { - when(attribute.getName()).thenReturn(CustomHeaderReader.HEADER_STRASSE); - when(attribute.getValue()).thenReturn(CustomHeaderTestFactory.STRASSE); - - var formData = reader.getHeader(document); - - assertThat(formData).containsEntry(CustomHeaderReader.HEADER_STRASSE, CustomHeaderTestFactory.STRASSE); - } - - @Test - void shouldAddPlz() { - when(attribute.getName()).thenReturn(CustomHeaderReader.HEADER_PLZ); - when(attribute.getValue()).thenReturn(CustomHeaderTestFactory.PLZ); - - var formData = reader.getHeader(document); - - assertThat(formData).containsEntry(CustomHeaderReader.HEADER_PLZ, CustomHeaderTestFactory.PLZ); - } - - @Test - void shouldAddOrt() { - when(attribute.getName()).thenReturn(CustomHeaderReader.HEADER_ORT); - when(attribute.getValue()).thenReturn(CustomHeaderTestFactory.ORT); - - var formData = reader.getHeader(document); - - assertThat(formData).containsEntry(CustomHeaderReader.HEADER_ORT, CustomHeaderTestFactory.ORT); - } - } - -} \ No newline at end of file diff --git a/intelliform-adapter/src/test/java/de/ozgcloud/eingang/intelliform/CustomHeaderTestFactory.java b/intelliform-adapter/src/test/java/de/ozgcloud/eingang/intelliform/CustomHeaderTestFactory.java deleted file mode 100644 index acb9fede61f17309e4417fac7149f5d03177c588..0000000000000000000000000000000000000000 --- a/intelliform-adapter/src/test/java/de/ozgcloud/eingang/intelliform/CustomHeaderTestFactory.java +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright (C) 2022 Das Land Schleswig-Holstein vertreten durch den - * Ministerpräsidenten des Landes Schleswig-Holstein - * Staatskanzlei - * Abteilung Digitalisierung und zentrales IT-Management der Landesregierung - * - * Lizenziert unter der EUPL, Version 1.2 oder - sobald - * diese von der Europäischen Kommission genehmigt wurden - - * Folgeversionen der EUPL ("Lizenz"); - * Sie dürfen dieses Werk ausschließlich gemäß - * dieser Lizenz nutzen. - * Eine Kopie der Lizenz finden Sie hier: - * - * https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 - * - * Sofern nicht durch anwendbare Rechtsvorschriften - * gefordert oder in schriftlicher Form vereinbart, wird - * die unter der Lizenz verbreitete Software "so wie sie - * ist", OHNE JEGLICHE GEWÄHRLEISTUNG ODER BEDINGUNGEN - - * ausdrücklich oder stillschweigend - verbreitet. - * Die sprachspezifischen Genehmigungen und Beschränkungen - * unter der Lizenz sind dem Lizenztext zu entnehmen. - */ -package de.ozgcloud.eingang.intelliform; - - -import java.util.HashMap; -import java.util.Map; - -public class CustomHeaderTestFactory { - - public static final String POSTFACH_ID = "postfach_id"; - public static final String VORNAME = "vorname"; - public static final String NACHNAME = "nachname"; - public static final String GEBURTSNAME = "geburtsname"; - public static final String GEBURTSORT = "geburtsort"; - public static final String EMAIL = "email"; - public static final String TELEFON = "telefon"; - public static final String STRASSE = "strasse"; - public static final String PLZ = "plz"; - public static final String ORT = "ort"; - - public static Map<String, Object> create() { - var map = new HashMap<String, Object>(); - map.put(CustomHeaderReader.HEADER_POSTFACH_ID, POSTFACH_ID); - map.put(CustomHeaderReader.HEADER_VORNAME, VORNAME); - map.put(CustomHeaderReader.HEADER_NACHNAME, NACHNAME); - map.put(CustomHeaderReader.HEADER_GEBURTSNAME, GEBURTSNAME); - map.put(CustomHeaderReader.HEADER_GEBURTSORT, GEBURTSORT); - map.put(CustomHeaderReader.HEADER_EMAIL, EMAIL); - map.put(CustomHeaderReader.HEADER_TELEFON, TELEFON); - map.put(CustomHeaderReader.HEADER_STRASSE, STRASSE); - map.put(CustomHeaderReader.HEADER_PLZ, PLZ); - map.put(CustomHeaderReader.HEADER_ORT, ORT); - return map; - } - -} diff --git a/intelliform-adapter/src/main/java/de/ozgcloud/eingang/SemantikAdapterConfiguration.java b/intelliform-adapter/src/test/java/de/ozgcloud/eingang/intelliform/DepositDataTestFactory.java similarity index 62% rename from intelliform-adapter/src/main/java/de/ozgcloud/eingang/SemantikAdapterConfiguration.java rename to intelliform-adapter/src/test/java/de/ozgcloud/eingang/intelliform/DepositDataTestFactory.java index 7c70b8144a3b5da22da7b1962216c9ada61dceba..7165a5489715577ac427f064bbfdea6103b01a4b 100644 --- a/intelliform-adapter/src/main/java/de/ozgcloud/eingang/SemantikAdapterConfiguration.java +++ b/intelliform-adapter/src/test/java/de/ozgcloud/eingang/intelliform/DepositDataTestFactory.java @@ -21,20 +21,23 @@ * Die sprachspezifischen Genehmigungen und Beschränkungen * unter der Lizenz sind dem Lizenztext zu entnehmen. */ -package de.ozgcloud.eingang; +package de.ozgcloud.eingang.intelliform; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; +import java.util.Collection; +import java.util.List; -import de.ozgcloud.eingang.semantik.enginebased.EngineBasedSemantikAdapter; -import de.ozgcloud.eingang.semantik.enginebased.afm.AfmEngineBasedAdapter; +public class DepositDataTestFactory { -@Configuration -public class SemantikAdapterConfiguration { + public static final List<Attachment> ATTACHMENTS = List.of( + AttachmentTestFactory.createXmlDaten(), + AttachmentTestFactory.createPdf(), + AttachmentTestFactory.createPng() + ); - @Bean - public EngineBasedSemantikAdapter engineBasedSemantikAdapter() { - return new AfmEngineBasedAdapter(); + public static DepositData create(Collection<Attachment> attachments) { + var depositData = new DepositData(); + depositData.setPrimaryDataAttachmentId(AttachmentTestFactory.XML_ATTACHMENT_ID); + depositData.getAttachments().addAll(attachments); + return depositData; } - -} \ No newline at end of file +} diff --git a/intelliform-adapter/src/test/java/de/ozgcloud/eingang/intelliform/DepositRequestIncomingFileMapperTest.java b/intelliform-adapter/src/test/java/de/ozgcloud/eingang/intelliform/DepositRequestIncomingFileMapperTest.java deleted file mode 100644 index 2ae6057c37562eedfee982df019ca6be54bcc7d0..0000000000000000000000000000000000000000 --- a/intelliform-adapter/src/test/java/de/ozgcloud/eingang/intelliform/DepositRequestIncomingFileMapperTest.java +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Copyright (C) 2022 Das Land Schleswig-Holstein vertreten durch den - * Ministerpräsidenten des Landes Schleswig-Holstein - * Staatskanzlei - * Abteilung Digitalisierung und zentrales IT-Management der Landesregierung - * - * Lizenziert unter der EUPL, Version 1.2 oder - sobald - * diese von der Europäischen Kommission genehmigt wurden - - * Folgeversionen der EUPL ("Lizenz"); - * Sie dürfen dieses Werk ausschließlich gemäß - * dieser Lizenz nutzen. - * Eine Kopie der Lizenz finden Sie hier: - * - * https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 - * - * Sofern nicht durch anwendbare Rechtsvorschriften - * gefordert oder in schriftlicher Form vereinbart, wird - * die unter der Lizenz verbreitete Software "so wie sie - * ist", OHNE JEGLICHE GEWÄHRLEISTUNG ODER BEDINGUNGEN - - * ausdrücklich oder stillschweigend - verbreitet. - * Die sprachspezifischen Genehmigungen und Beschränkungen - * unter der Lizenz sind dem Lizenztext zu entnehmen. - */ -package de.ozgcloud.eingang.intelliform; - -import static org.assertj.core.api.Assertions.*; - -import java.util.List; - -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; - -import de.ozgcloud.eingang.common.formdata.IncomingFile; - -class DepositRequestIncomingFileMapperTest { - - private DepositRequestIncomingFileMapper mapper; - - @BeforeEach - void init() { - - mapper = new DepositRequestIncomingFileMapper(); - } - - @Test - void validateFileCount() { - - List<IncomingFile> files = mapper.mapFiles(DepositTestFactory.create()); - - assertThat(files).isNotEmpty().hasSize(2); - } - - @Test - void validateFile1() { - - List<IncomingFile> files = mapper.mapFiles(DepositTestFactory.create()); - - IncomingFile file = files.get(0); - assertThat(file.getContentStream()).hasBinaryContent(AttachmentTestFactory.XML_CONTENT); - assertThat(file.getContentType()).isEqualTo(AttachmentTestFactory.XML_CONTENT_TYPE); - assertThat(file.getVendorId()).isEqualTo(AttachmentTestFactory.XML_ID); - assertThat(file.getName()).isEqualTo(AttachmentTestFactory.XML_NAME); - assertThat(file.getId()).isNotNull(); - } -} diff --git a/intelliform-adapter/src/test/java/de/ozgcloud/eingang/intelliform/DepositTestFactory.java b/intelliform-adapter/src/test/java/de/ozgcloud/eingang/intelliform/DepositTestFactory.java deleted file mode 100644 index 174569a3e12d247dd7dc3ac4d9e9ca609298f858..0000000000000000000000000000000000000000 --- a/intelliform-adapter/src/test/java/de/ozgcloud/eingang/intelliform/DepositTestFactory.java +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright (C) 2022 Das Land Schleswig-Holstein vertreten durch den - * Ministerpräsidenten des Landes Schleswig-Holstein - * Staatskanzlei - * Abteilung Digitalisierung und zentrales IT-Management der Landesregierung - * - * Lizenziert unter der EUPL, Version 1.2 oder - sobald - * diese von der Europäischen Kommission genehmigt wurden - - * Folgeversionen der EUPL ("Lizenz"); - * Sie dürfen dieses Werk ausschließlich gemäß - * dieser Lizenz nutzen. - * Eine Kopie der Lizenz finden Sie hier: - * - * https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 - * - * Sofern nicht durch anwendbare Rechtsvorschriften - * gefordert oder in schriftlicher Form vereinbart, wird - * die unter der Lizenz verbreitete Software "so wie sie - * ist", OHNE JEGLICHE GEWÄHRLEISTUNG ODER BEDINGUNGEN - - * ausdrücklich oder stillschweigend - verbreitet. - * Die sprachspezifischen Genehmigungen und Beschränkungen - * unter der Lizenz sind dem Lizenztext zu entnehmen. - */ -package de.ozgcloud.eingang.intelliform; - -import java.util.List; - -import de.ozgcloud.eingang.common.formdata.IncomingFileTestFactory; - -public class DepositTestFactory { - - public static final String ATTACHMENT1_NAME = IncomingFileTestFactory.NAME; - public static final String ATTACHMENT1_ID = IncomingFileTestFactory.VENDOR_ID; - public static final String ATTACHMENT1_CONTENT_TYPE = IncomingFileTestFactory.CONTENT_TYPE; - public static final byte[] ATTACHMENT1_CONTENT = IncomingFileTestFactory.CONTENT; - - public static final String ATTACHMENT2_NAME = "Scan1.pdf"; - public static final String ATTACHMENT2_ID = "VendorId2222"; - public static final String ATTACHMENT2_CONTENT_TYPE = "application/pdf"; - public static final byte[] ATTACHMENT2_CONTENT = "TestContent2".getBytes(); - - public static final List<Attachment> ATTACHMENTS = List.of(AttachmentTestFactory.createXmlDaten(), AttachmentTestFactory.createPdf()); - - public static Deposit create() { - return DepositTestFactory.withAttachments(ATTACHMENTS); - } - - static Deposit withData(DepositData data) { - Deposit deposit = new Deposit(); - data.setPrimaryDataAttachmentId(AttachmentTestFactory.XML_ID); - deposit.setData(data); - - return deposit; - } - - static Deposit withAttachments(List<Attachment> attachments) { - Deposit deposit = DepositTestFactory.withData(new DepositData()); - deposit.getData().getAttachments().addAll(attachments); - return deposit; - } -} diff --git a/intelliform-adapter/src/test/java/de/ozgcloud/eingang/intelliform/FormDataIncomingFileMapperTest.java b/intelliform-adapter/src/test/java/de/ozgcloud/eingang/intelliform/FormDataIncomingFileMapperTest.java deleted file mode 100644 index 05d11ea152de2367bb23d51555764a15083103d9..0000000000000000000000000000000000000000 --- a/intelliform-adapter/src/test/java/de/ozgcloud/eingang/intelliform/FormDataIncomingFileMapperTest.java +++ /dev/null @@ -1,234 +0,0 @@ -/* - * Copyright (C) 2022 Das Land Schleswig-Holstein vertreten durch den - * Ministerpräsidenten des Landes Schleswig-Holstein - * Staatskanzlei - * Abteilung Digitalisierung und zentrales IT-Management der Landesregierung - * - * Lizenziert unter der EUPL, Version 1.2 oder - sobald - * diese von der Europäischen Kommission genehmigt wurden - - * Folgeversionen der EUPL ("Lizenz"); - * Sie dürfen dieses Werk ausschließlich gemäß - * dieser Lizenz nutzen. - * Eine Kopie der Lizenz finden Sie hier: - * - * https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 - * - * Sofern nicht durch anwendbare Rechtsvorschriften - * gefordert oder in schriftlicher Form vereinbart, wird - * die unter der Lizenz verbreitete Software "so wie sie - * ist", OHNE JEGLICHE GEWÄHRLEISTUNG ODER BEDINGUNGEN - - * ausdrücklich oder stillschweigend - verbreitet. - * Die sprachspezifischen Genehmigungen und Beschränkungen - * unter der Lizenz sind dem Lizenztext zu entnehmen. - */ -package de.ozgcloud.eingang.intelliform; - -import static org.assertj.core.api.Assertions.*; - -import java.io.ByteArrayInputStream; -import java.io.IOException; -import java.util.List; - -import javax.xml.parsers.DocumentBuilder; -import javax.xml.parsers.DocumentBuilderFactory; -import javax.xml.parsers.ParserConfigurationException; - -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Nested; -import org.junit.jupiter.api.Test; -import org.w3c.dom.Document; -import org.xml.sax.SAXException; - -import de.ozgcloud.common.test.TestUtils; -import de.ozgcloud.eingang.common.formdata.IncomingFile; -import de.ozgcloud.eingang.common.formdata.IncomingFileGroup; - -class FormDataIncomingFileMapperTest { - - FormDataIncomingFileMapper mapper = new FormDataIncomingFileMapper(); - - private Document document; - - @Test - void testBuildParentNodeName() { - - assertThat(mapper.buildParentNodeName("datei_ausweis-item")).isEqualTo("datei_ausweis"); - assertThat(mapper.buildParentNodeName("datei_ausweis")).isEqualTo("datei_ausweis"); - assertThat(mapper.buildParentNodeName("datei_-item-ausweis")).isEqualTo("datei_-item-ausweis"); - } - - @Nested - class TestEinfachesFormularMitZweiAnhaengen { - - private static final String GROUP1NAME = "Upload1"; - private static final String GROUP2NAME = "Upload2"; - - List<IncomingFileGroup> attachments; - - @BeforeEach - void init() throws ParserConfigurationException, SAXException, IOException { - - String xml = TestUtils.loadTextFile("intelliform/EinfachesFormularZweiAnhaengeXmlDaten1.xml"); - - document = buildDocument(xml); - - attachments = mapper.mapAttachments(document); - } - - @Test - void validateAttachmentGroupCount() { - - assertThat(attachments).hasSize(2); - } - - @Test - void validateGroup1Name() { - - assertThat(attachments.get(0).getName()).isEqualTo(GROUP1NAME); - } - - @Test - void validateGroup1FilesCount() { - - assertThat(attachments.get(0).getFiles()).hasSize(1); - } - - @Test - void validateGroup1File() { - - IncomingFile file = attachments.get(0).getFiles().get(0); - - assertThat(file.getId()).isNotNull().hasSize(36); - assertThat(file.getVendorId()).isEqualTo("assistants.E0FBA361C191F8B723949467AE302BEA24E4745E"); - assertThat(file.getName()).isEqualTo("Helge1.jpg"); - assertThat(file.getContentType()).isEqualTo("image/jpeg"); - assertThat(file.getSize()).isEqualTo(155251); - } - - @Test - void validateGroup2Name() { - - assertThat(attachments.get(1).getName()).isEqualTo(GROUP2NAME); - } - - @Test - void validateGroup2FilesCount() { - - assertThat(attachments.get(1).getFiles()).hasSize(1); - } - - @Test - void validateGroup2File() { - - IncomingFile file = attachments.get(1).getFiles().get(0); - - assertThat(file.getId()).isNotNull().hasSize(36); - assertThat(file.getVendorId()).isEqualTo("assistants.52D79E5B2118D1740045AB87151535DCAD24E9A7"); - assertThat(file.getName()).isEqualTo("Helgetext2.odt"); - assertThat(file.getContentType()).isEqualTo("application/vnd.oasis.opendocument.text"); - assertThat(file.getSize()).isEqualTo(7993); - } - } - - @Nested - class TestEinfachesFormularMitZweiAnhaengenVerschachtelt { - - private static final String GROUP1NAME = "datei_ausweis"; - private static final String GROUP2NAME = "datei_meldebestaetigung"; - - List<IncomingFileGroup> attachments; - - @BeforeEach - void init() throws ParserConfigurationException, SAXException, IOException { - - String xml = TestUtils.loadTextFile("intelliform/EinfachesFormularZweiAnhaengeXmlDatenVerschachtelt.xml"); - - document = buildDocument(xml); - - attachments = mapper.mapAttachments(document); - } - - @Test - void validateAttachmentGroupCount() { - - assertThat(attachments).hasSize(2); - } - - @Test - void validateGroup1Name() { - - assertThat(attachments.get(0).getName()).isEqualTo(GROUP1NAME); - } - - @Test - void validateGroup1FilesCount() { - - assertThat(attachments.get(0).getFiles()).hasSize(2); - } - - @Test - void validateGroup1File1() { - - IncomingFile file = attachments.get(0).getFiles().get(0); - - assertThat(file.getId()).isNotNull().hasSize(36); - assertThat(file.getVendorId()).isEqualTo("assistants.21B483DAA2DC7900C1D1135E566D0F672CB42832"); - assertThat(file.getName()).isEqualTo("20210326_133516[1].jpg"); - assertThat(file.getContentType()).isEqualTo("image/jpeg"); - assertThat(file.getSize()).isEqualTo(1184319); - } - - @Test - void validateGroup1File2() { - - IncomingFile file = attachments.get(0).getFiles().get(1); - - assertThat(file.getId()).isNotNull().hasSize(36); - assertThat(file.getVendorId()).isEqualTo("assistants.2F1FF737CF4F23191C1952091CB342254EE22A37"); - assertThat(file.getName()).isEqualTo("20210326_133526[1].jpg"); - assertThat(file.getContentType()).isEqualTo("image/jpeg"); - assertThat(file.getSize()).isEqualTo(1384037); - } - - @Test - void validateGroup2Name() { - - assertThat(attachments.get(1).getName()).isEqualTo(GROUP2NAME); - } - - @Test - void validateGroup2FilesCount() { - - assertThat(attachments.get(1).getFiles()).hasSize(1); - } - - @Test - void validateGroup2File() { - - IncomingFile file = attachments.get(1).getFiles().get(0); - - assertThat(file.getId()).isNotNull().hasSize(36); - assertThat(file.getVendorId()).isEqualTo("assistants.B20451156C677116B91A4EF2D1E859837B6CE510"); - assertThat(file.getName()).isEqualTo("20210324_103054[1].jpg"); - assertThat(file.getContentType()).isEqualTo("image/jpeg"); - assertThat(file.getSize()).isEqualTo(3066416); - } - } - - private Document buildDocument(String xml) throws ParserConfigurationException, SAXException, IOException { - - DocumentBuilderFactory docBuilderFactory = DocumentBuilderFactory.newInstance(); - - docBuilderFactory.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true); - - DocumentBuilder docBuilder = docBuilderFactory.newDocumentBuilder(); - Document document = docBuilder.parse(new ByteArrayInputStream(xml.getBytes())); - - // optional, but recommended - // http://stackoverflow.com/questions/13786607/normalization-in-dom-parsing-with-java-how-does-it-work - document.getDocumentElement().normalize(); - - return document; - } - -} diff --git a/intelliform-adapter/src/test/java/de/ozgcloud/eingang/intelliform/FormDataEndpointITCase.java b/intelliform-adapter/src/test/java/de/ozgcloud/eingang/intelliform/IntelliFormEndpointITCase.java similarity index 99% rename from intelliform-adapter/src/test/java/de/ozgcloud/eingang/intelliform/FormDataEndpointITCase.java rename to intelliform-adapter/src/test/java/de/ozgcloud/eingang/intelliform/IntelliFormEndpointITCase.java index 2e87bcbd6b297b71c4ece2afa451f258dcae239a..f3144df49776743796da29d54369d4b29e444983 100644 --- a/intelliform-adapter/src/test/java/de/ozgcloud/eingang/intelliform/FormDataEndpointITCase.java +++ b/intelliform-adapter/src/test/java/de/ozgcloud/eingang/intelliform/IntelliFormEndpointITCase.java @@ -56,7 +56,7 @@ import de.ozgcloud.vorgang.vorgang.GrpcIncomingFileGroup; import lombok.SneakyThrows; @SpringBootTest -class FormDataEndpointITCase { +class IntelliFormEndpointITCase { private final static String TEST_FILE_PATH = "classpath:itcase/"; diff --git a/intelliform-adapter/src/test/java/de/ozgcloud/eingang/intelliform/FormDataEndpointTest.java b/intelliform-adapter/src/test/java/de/ozgcloud/eingang/intelliform/IntelliFormEndpointTest.java similarity index 88% rename from intelliform-adapter/src/test/java/de/ozgcloud/eingang/intelliform/FormDataEndpointTest.java rename to intelliform-adapter/src/test/java/de/ozgcloud/eingang/intelliform/IntelliFormEndpointTest.java index c6c9381d3ca42453ede63033b277c7e1d00261ef..2466e3842775333cc2926f507463ce42cc898bff 100644 --- a/intelliform-adapter/src/test/java/de/ozgcloud/eingang/intelliform/FormDataEndpointTest.java +++ b/intelliform-adapter/src/test/java/de/ozgcloud/eingang/intelliform/IntelliFormEndpointTest.java @@ -42,23 +42,23 @@ import de.ozgcloud.common.test.TestUtils; import de.ozgcloud.eingang.common.formdata.FormDataTestFactory; import de.ozgcloud.eingang.semantik.SemantikAdapter; -class FormDataEndpointTest { +class IntelliFormEndpointTest { @InjectMocks - private FormDataEndpoint formdataEndpoint; + private IntelliFormEndpoint formdataEndpointIntelli; @Mock - private SemantikFormDataMapper semantikFormDataMapper; + private IntelliFormMapper intelliFormMapper; @Mock private SemantikAdapter semantikAdapter; @BeforeEach void init() throws SAXException, IOException, ParserConfigurationException { - when(semantikFormDataMapper.mapToFormData(any())).thenReturn(FormDataTestFactory.create()); + when(intelliFormMapper.mapToFormData(any())).thenReturn(FormDataTestFactory.create()); } @Test void testDepositFormData() throws SAXException, IOException, ParserConfigurationException, URISyntaxException { - var response = formdataEndpoint.inputFormData(buildRequest("intelliform/XML-Daten-1.xml")); + var response = formdataEndpointIntelli.inputFormData(buildRequest("intelliform/XML-Daten-1.xml")); assertThat(response).isNotNull(); } diff --git a/intelliform-adapter/src/test/java/de/ozgcloud/eingang/intelliform/IntelliFormMapperTest.java b/intelliform-adapter/src/test/java/de/ozgcloud/eingang/intelliform/IntelliFormMapperTest.java new file mode 100644 index 0000000000000000000000000000000000000000..c394c2b2ee230d008e392252f11067af34032d74 --- /dev/null +++ b/intelliform-adapter/src/test/java/de/ozgcloud/eingang/intelliform/IntelliFormMapperTest.java @@ -0,0 +1,207 @@ +/* + * Copyright (C) 2022 Das Land Schleswig-Holstein vertreten durch den + * Ministerpräsidenten des Landes Schleswig-Holstein + * Staatskanzlei + * Abteilung Digitalisierung und zentrales IT-Management der Landesregierung + * + * Lizenziert unter der EUPL, Version 1.2 oder - sobald + * diese von der Europäischen Kommission genehmigt wurden - + * Folgeversionen der EUPL ("Lizenz"); + * Sie dürfen dieses Werk ausschließlich gemäß + * dieser Lizenz nutzen. + * Eine Kopie der Lizenz finden Sie hier: + * + * https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 + * + * Sofern nicht durch anwendbare Rechtsvorschriften + * gefordert oder in schriftlicher Form vereinbart, wird + * die unter der Lizenz verbreitete Software "so wie sie + * ist", OHNE JEGLICHE GEWÄHRLEISTUNG ODER BEDINGUNGEN - + * ausdrücklich oder stillschweigend - verbreitet. + * Die sprachspezifischen Genehmigungen und Beschränkungen + * unter der Lizenz sind dem Lizenztext zu entnehmen. + */ +package de.ozgcloud.eingang.intelliform; + +import static de.ozgcloud.eingang.intelliform.AttachmentTestFactory.*; +import static de.ozgcloud.eingang.intelliform.DepositDataTestFactory.*; +import static org.assertj.core.api.Assertions.*; +import static org.mockito.Mockito.*; + +import java.nio.charset.Charset; +import java.util.Collections; +import java.util.List; + +import org.apache.commons.io.FileUtils; +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.mockito.Spy; + +import de.ozgcloud.eingang.common.errorhandling.TechnicalException; +import de.ozgcloud.eingang.common.formdata.FormData; +import de.ozgcloud.eingang.common.formdata.IncomingFile; +import lombok.SneakyThrows; + +class IntelliFormMapperTest { + + @Spy + private IntelliFormMapper mapper; + + @DisplayName("map to form data") + @Nested + class TestMapToFormData { + + @Captor + private ArgumentCaptor<Attachment> attachmentArgumentCaptor; + + private DepositData depositData; + + @DisplayName("with normal attachments") + @Nested + class TestWithNormalAttachments { + @BeforeEach + void mock() { + depositData = DepositDataTestFactory.create(ATTACHMENTS); + } + + @DisplayName("should throw technical exception if primary xml link is incorrect") + @Test + void shouldThrowTechnicalExceptionIfPrimaryXmlLinkIsIncorrect() { + depositData.setPrimaryDataAttachmentId("incorrect"); + + assertThatThrownBy(TestMapToFormData.this::doMapping) + .isInstanceOf(TechnicalException.class); + } + + @DisplayName("should use map to incoming file method") + @Test + void shouldUseMapToIncomingFileMethod() { + doMapping(); + verify(mapper, times(ATTACHMENTS.size())).mapAttachmentToIncomingFile(attachmentArgumentCaptor.capture()); + + assertThat(attachmentArgumentCaptor.getAllValues()).isEqualTo(ATTACHMENTS); + } + + @DisplayName("should return with representations") + @Test + void shouldReturnWithRepresentations() { + var formData = doMapping(); + + var incomingFileIds = formData.getRepresentations().stream().map(IncomingFile::getVendorId).toList(); + assertThat(incomingFileIds).contains(XML_ATTACHMENT_ID, PDF_ATTACHMENT_ID); + } + + @DisplayName("should return with attachments") + @Test + void shouldReturnWithAttachments() { + var formData = doMapping(); + + var incomingFileIds = formData.getAttachments().stream() + .flatMap(group -> group.getFiles().stream()) + .map(IncomingFile::getVendorId) + .toList(); + assertThat(incomingFileIds).contains(PNG_ATTACHMENT_ID); + } + + @DisplayName("should return with number of representations") + @Test + void shouldReturnWithNumberOfRepresentations() { + var formData = doMapping(); + + assertThat(formData.getNumberOfRepresentations()).isEqualTo(2); + } + } + + @DisplayName("with empty attachments") + @Nested + class TestWithEmptyAttachments { + @DisplayName("should throw technical exception") + @Test + void shouldThrowTechnicalException() { + depositData = DepositDataTestFactory.create(Collections.emptyList()); + + assertThatThrownBy(TestMapToFormData.this::doMapping) + .isInstanceOf(TechnicalException.class); + } + } + + private FormData doMapping() { + return mapper.mapToFormData(depositData); + } + + private List<String> expectedAttachmentIds(List<Attachment> attachmentList) { + return attachmentList.stream().map(attachment -> attachment.id).toList(); + } + + } + + @DisplayName("map attachment to incoming file") + @Nested + class TestMapAttachmentToIncomingFile { + private Attachment attachment; + + @BeforeEach + void mock() { + attachment = AttachmentTestFactory.createXmlDaten(); + } + + @DisplayName("should have ID") + @Test + void shouldHaveId() { + var incomingFile = doMapping(); + + assertThat(incomingFile.getId()).isNotNull(); + } + + @DisplayName("should have vendor ID") + @Test + void shouldHaveVendorId() { + var incomingFile = doMapping(); + + assertThat(incomingFile.getVendorId()).isEqualTo(XML_ATTACHMENT_ID); + } + + @DisplayName("should have name") + @Test + void shouldHaveName() { + var incomingFile = doMapping(); + + assertThat(incomingFile.getName()).isEqualTo(XML_NAME); + } + + @DisplayName("should have content type") + @Test + void shouldHaveContentType() { + var incomingFile = doMapping(); + + assertThat(incomingFile.getName()).isEqualTo(XML_NAME); + } + + @DisplayName("should have size") + @Test + void shouldHaveSize() { + var incomingFile = doMapping(); + + assertThat(incomingFile.getSize()).isEqualTo(XML_CONTENT.length); + } + + @DisplayName("should have file with content") + @SneakyThrows + @Test + void shouldHaveFileWithContent() { + var incomingFile = doMapping(); + + var content = FileUtils.readFileToString(incomingFile.getFile(), Charset.defaultCharset()); + assertThat(content).isEqualTo(XML_CONTENT_STRING); + } + + private IncomingFile doMapping() { + return mapper.mapAttachmentToIncomingFile(attachment); + } + } + +} diff --git a/intelliform-adapter/src/test/java/de/ozgcloud/eingang/intelliform/RepresentationsCalculatorTest.java b/intelliform-adapter/src/test/java/de/ozgcloud/eingang/intelliform/RepresentationsCalculatorTest.java deleted file mode 100644 index 36ac0cb7e2cff2cd68c210262b7d1360b8a68d9e..0000000000000000000000000000000000000000 --- a/intelliform-adapter/src/test/java/de/ozgcloud/eingang/intelliform/RepresentationsCalculatorTest.java +++ /dev/null @@ -1,88 +0,0 @@ -/* - * Copyright (C) 2022 Das Land Schleswig-Holstein vertreten durch den - * Ministerpräsidenten des Landes Schleswig-Holstein - * Staatskanzlei - * Abteilung Digitalisierung und zentrales IT-Management der Landesregierung - * - * Lizenziert unter der EUPL, Version 1.2 oder - sobald - * diese von der Europäischen Kommission genehmigt wurden - - * Folgeversionen der EUPL ("Lizenz"); - * Sie dürfen dieses Werk ausschließlich gemäß - * dieser Lizenz nutzen. - * Eine Kopie der Lizenz finden Sie hier: - * - * https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 - * - * Sofern nicht durch anwendbare Rechtsvorschriften - * gefordert oder in schriftlicher Form vereinbart, wird - * die unter der Lizenz verbreitete Software "so wie sie - * ist", OHNE JEGLICHE GEWÄHRLEISTUNG ODER BEDINGUNGEN - - * ausdrücklich oder stillschweigend - verbreitet. - * Die sprachspezifischen Genehmigungen und Beschränkungen - * unter der Lizenz sind dem Lizenztext zu entnehmen. - */ -package de.ozgcloud.eingang.intelliform; - -import static org.assertj.core.api.Assertions.*; - -import java.util.List; - -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Nested; -import org.junit.jupiter.api.Test; - -import de.ozgcloud.eingang.common.formdata.IncomingFile; -import de.ozgcloud.eingang.common.formdata.IncomingFileGroup; -import de.ozgcloud.eingang.common.formdata.IncomingFileGroupTestFactory; -import de.ozgcloud.eingang.common.formdata.IncomingFileTestFactory; - -class RepresentationsCalculatorTest { - - private static final String REPRESENTATION_VENDOR_ID_1 = "REPRESENTATION_VENDOR_ID_1"; - private static final String REPRESENTATION_VENDOR_ID_2 = "REPRESENTATION_VENDOR_ID_2"; - - private RepresentationsCalculator service; - - @BeforeEach - void init() { - - service = new RepresentationsCalculator(); - } - - @Nested - class CalculateRepresentations { - - private List<IncomingFile> representations; - - @BeforeEach - void init() { - - List<IncomingFile> depositDataFiles = List.of( - IncomingFileTestFactory.createBuilder().vendorId(REPRESENTATION_VENDOR_ID_1).build(), - IncomingFileTestFactory.create(), - IncomingFileTestFactory.createBuilder().vendorId(REPRESENTATION_VENDOR_ID_2).build()); - - List<IncomingFileGroup> formDataFileGroups = List.of(IncomingFileGroupTestFactory.create()); - - representations = service.calculateRepresentations(formDataFileGroups, depositDataFiles); - } - - @Test - void calculateRepresentations() { - - assertThat(representations).hasSize(2); - } - - @Test - void validateRepresentation1() { - - assertThat(representations.get(0).getVendorId()).isEqualTo(REPRESENTATION_VENDOR_ID_1); - } - - @Test - void validateRepresentation2() { - - assertThat(representations.get(1).getVendorId()).isEqualTo(REPRESENTATION_VENDOR_ID_2); - } - } -} diff --git a/intelliform-adapter/src/test/java/de/ozgcloud/eingang/intelliform/SemantikFormDataMapperTest.java b/intelliform-adapter/src/test/java/de/ozgcloud/eingang/intelliform/SemantikFormDataMapperTest.java deleted file mode 100644 index 3bf90315f3d0be4e23ea2de093908455ad32b18e..0000000000000000000000000000000000000000 --- a/intelliform-adapter/src/test/java/de/ozgcloud/eingang/intelliform/SemantikFormDataMapperTest.java +++ /dev/null @@ -1,172 +0,0 @@ -/* - * Copyright (C) 2022 Das Land Schleswig-Holstein vertreten durch den - * Ministerpräsidenten des Landes Schleswig-Holstein - * Staatskanzlei - * Abteilung Digitalisierung und zentrales IT-Management der Landesregierung - * - * Lizenziert unter der EUPL, Version 1.2 oder - sobald - * diese von der Europäischen Kommission genehmigt wurden - - * Folgeversionen der EUPL ("Lizenz"); - * Sie dürfen dieses Werk ausschließlich gemäß - * dieser Lizenz nutzen. - * Eine Kopie der Lizenz finden Sie hier: - * - * https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 - * - * Sofern nicht durch anwendbare Rechtsvorschriften - * gefordert oder in schriftlicher Form vereinbart, wird - * die unter der Lizenz verbreitete Software "so wie sie - * ist", OHNE JEGLICHE GEWÄHRLEISTUNG ODER BEDINGUNGEN - - * ausdrücklich oder stillschweigend - verbreitet. - * Die sprachspezifischen Genehmigungen und Beschränkungen - * unter der Lizenz sind dem Lizenztext zu entnehmen. - */ -package de.ozgcloud.eingang.intelliform; - -import static de.ozgcloud.eingang.common.formdata.IncomingFileGroupTestFactory.*; -import static org.assertj.core.api.Assertions.*; -import static org.mockito.ArgumentMatchers.*; -import static org.mockito.Mockito.*; - -import java.io.IOException; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import javax.xml.parsers.ParserConfigurationException; - -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Nested; -import org.junit.jupiter.api.Test; -import org.mockito.Mock; -import org.xml.sax.SAXException; - -import de.ozgcloud.eingang.common.formdata.FormData; -import de.ozgcloud.eingang.common.formdata.IncomingFile; -import de.ozgcloud.eingang.semantik.enginebased.FilesMapperHelper; - -class SemantikFormDataMapperTest { - - private SemantikFormDataMapper mapper; - - @Mock - private CustomHeaderReader customHeaderReader; - - @BeforeEach - void setup() { - mapper = new SemantikFormDataMapper(new XmlToJavaMapsMapper(), new FormDataIncomingFileMapper(), - new RepresentationsCalculator(), new DepositRequestIncomingFileMapper(), new AttachmentsContentAdder(), customHeaderReader); - } - - @Nested - class TestMapFormData { - - private final Deposit deposit = DepositTestFactory.create(); - - @Test - void shouldMapIdField() throws SAXException, IOException, ParserConfigurationException { - var formData = mapToFormData(deposit); - - assertThat(formData.getId()).isNotNull(); - } - - @Test - void shouldRemoveFileReferences() { - Map<String, Object> formDataMap = new HashMap<>(Map.of(FILE_REF1, Map.of(SemantikFormDataMapper.FILE, Map.of(ID, VENDOR_ID_XXX)))); - - mapper.removeMappedFileReferences(FILE_GROUPS, formDataMap); - - assertThat(formDataMap).doesNotContainKey(FILE_REF1); - } - - @Nested - class TestMapDepositRepresentations { - - @Test - void shouldMap() throws SAXException, IOException, ParserConfigurationException { - var formData = mapToFormData(deposit); - - assertThat(getRepresentations(formData)).hasSize(2); - } - - @Test - void shouldContainsXmlData() { - var formData = mapToFormData(deposit); - - var xmlRepresentation = getRepresentations(formData).stream() - .filter(xml -> xml.getContentType().equals(AttachmentTestFactory.XML_CONTENT_TYPE)).findFirst(); - assertThat(xmlRepresentation).isPresent(); - } - - @Test - void shouldContainsPdfData() { - var formData = mapToFormData(deposit); - - var pdfRepresentation = getRepresentations(formData).stream() - .filter(pdf -> pdf.getContentType().equals(AttachmentTestFactory.PDF_ATTACHMENT_CONTENT_TYPE)).findFirst(); - assertThat(pdfRepresentation).isPresent(); - } - - @Test - void shouldContainsPdfAttributes() { - var formData = mapToFormData(deposit); - - var pdfAttachment = getRepresentations(formData).stream() - .filter(pdf -> pdf.getContentType().equals(AttachmentTestFactory.PDF_ATTACHMENT_CONTENT_TYPE)).findFirst(); - - assertThat(pdfAttachment).isPresent(); - assertThat(pdfAttachment.get().getContentType()).isEqualTo(AttachmentTestFactory.PDF_ATTACHMENT_CONTENT_TYPE); - assertThat(pdfAttachment.get().getVendorId()).isEqualTo(AttachmentTestFactory.PDF_ATTACHMENT_ID); - assertThat(pdfAttachment.get().getName()).isEqualTo(AttachmentTestFactory.PDF_ATTACHMENT_NAME); - assertThat(pdfAttachment.get().getContentStream()).hasBinaryContent(AttachmentTestFactory.PDF_ATTACHMENT_CONTENT); - } - - @SuppressWarnings("unchecked") - private List<IncomingFile> getRepresentations(FormData formData) { - return (List<IncomingFile>) ((Map<String, Object>) formData.getFormData().get(FilesMapperHelper.FIELD_NAME_MAPPED_FILES)) - .get(FilesMapperHelper.REPRESENTATIONS); - } - } - - @Nested - class TestMapHeader { - - @Test - void shouldMapHeader() { - var formData = mapToFormData(deposit); - - var formHeader = getHeader(formData); - assertThat(formHeader) - .containsEntry(SemantikFormDataMapper.HEADER_ID, "20201118365670866101") - .containsEntry(SemantikFormDataMapper.HEADER_TIMESTAMP, "2020-11-18T09:09:27.627Z") - .containsEntry(SemantikFormDataMapper.HEADER_FORM_ID, "waffen/kleinerWaffenschein") - .containsEntry(SemantikFormDataMapper.HEADER_FORM, "Kleiner Waffenschein gem. § 10 Abs. 4 Satz 4 Waffengesetz (WaffG)") - .containsEntry(SemantikFormDataMapper.HEADER_SENDER, "afm.schleswig-holstein.de") - .containsEntry(SemantikFormDataMapper.HEADER_CUSTOMER, "Einheitlicher Ansprechpartner") - .containsEntry(SemantikFormDataMapper.HEADER_CUSTOMER_ID, "ea-sh") - .containsEntry(SemantikFormDataMapper.HEADER_CLIENT, "Schleswig-Holstein") - .containsEntry(SemantikFormDataMapper.HEADER_CLIENT_ID, "land"); - } - - @Test - void shouldAddBayernHeader() { - Map<String, Object> bayernHeader = Map.of(CustomHeaderReader.HEADER_POSTFACH_ID, CustomHeaderTestFactory.POSTFACH_ID); - when(customHeaderReader.getHeader(any())).thenReturn(bayernHeader); - - var formData = mapToFormData(deposit); - - verify(customHeaderReader).getHeader(any()); - assertThat(getHeader(formData)).containsEntry(CustomHeaderReader.HEADER_POSTFACH_ID, CustomHeaderTestFactory.POSTFACH_ID); - } - - @SuppressWarnings("unchecked") - private Map<String, Object> getHeader(FormData formData) { - return (Map<String, Object>) formData.getFormData().get(SemantikFormDataMapper.HEADER_FIELD); - } - } - - private FormData mapToFormData(Deposit deposit) { - return mapper.mapToFormData(deposit); - } - } -} \ No newline at end of file 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 74840e2f51139b08cf49bb19bb7016a71dfa2bd9..ccf6f3ce4aad5162e9364c079bf07856bdc74a1d 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 @@ -23,7 +23,8 @@ */ package de.ozgcloud.eingang.semantik; -import java.util.Objects; +import java.util.List; +import java.util.Optional; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; @@ -32,15 +33,15 @@ import de.ozgcloud.eingang.common.formdata.FormData; import de.ozgcloud.eingang.router.VorgangService; import de.ozgcloud.eingang.semantik.enginebased.EngineBasedSemantikAdapter; import de.ozgcloud.eingang.semantik.formbased.FormBasedSemantikAdapter; +import lombok.RequiredArgsConstructor; @Service public class SemantikAdapter { - @Autowired(required = false) - private EngineBasedSemantikAdapter engineBasedAdapter; + @Autowired + private List<EngineBasedSemantikAdapter> engineBasedAdapters; @Autowired private FormBasedSemantikAdapter formBasedAdapter; - @Autowired private VorgangService vorgangService; @@ -52,13 +53,18 @@ public class SemantikAdapter { } private FormData parseByEngineAdapter(FormData formData) { - if (Objects.nonNull(engineBasedAdapter)) { - return engineBasedAdapter.parseFormData(formData); - } - return formData; + return findResponsibleEngineAdapter(formData) + .map(adapter -> adapter.parseFormData(formData)) + .orElse(formData); + } + + Optional<EngineBasedSemantikAdapter> findResponsibleEngineAdapter(FormData formData) { + return engineBasedAdapters.stream() + .filter(adapter -> adapter.isResponsible(formData)) + .findFirst(); } private FormData parseByFormAdapter(FormData formData) { return formBasedAdapter.parseFormData(formData); } -} \ No newline at end of file +} diff --git a/semantik-adapter/src/main/java/de/ozgcloud/eingang/semantik/enginebased/EngineBasedSemantikAdapter.java b/semantik-adapter/src/main/java/de/ozgcloud/eingang/semantik/enginebased/EngineBasedSemantikAdapter.java index 866b8fc52a49b92460625922df950f46224a6043..a60d4a859c5074a52b634121dedc678ad9bf6e6e 100644 --- a/semantik-adapter/src/main/java/de/ozgcloud/eingang/semantik/enginebased/EngineBasedSemantikAdapter.java +++ b/semantik-adapter/src/main/java/de/ozgcloud/eingang/semantik/enginebased/EngineBasedSemantikAdapter.java @@ -28,4 +28,9 @@ import de.ozgcloud.eingang.common.formdata.FormData; public interface EngineBasedSemantikAdapter { FormData parseFormData(FormData formData); + + @SuppressWarnings("unused") + default boolean isResponsible(FormData formData) { + return true; + } } diff --git a/semantik-adapter/src/main/java/de/ozgcloud/eingang/semantik/enginebased/afm/AfmAntragstellerMapper.java b/semantik-adapter/src/main/java/de/ozgcloud/eingang/semantik/enginebased/afm/AfmAntragstellerMapper.java index 4e5251da5812a678dd2234ab964de002cabd78e8..8ca005996ebcd86ce4b59b03f9cc087ac3c3569a 100644 --- a/semantik-adapter/src/main/java/de/ozgcloud/eingang/semantik/enginebased/afm/AfmAntragstellerMapper.java +++ b/semantik-adapter/src/main/java/de/ozgcloud/eingang/semantik/enginebased/afm/AfmAntragstellerMapper.java @@ -81,11 +81,11 @@ class AfmAntragstellerMapper implements AfmEngineBasedMapper { return (String) formDataMap.get(POSTFACH_ID); } - @SuppressWarnings("unchecked") - private Optional<Map<String, Object>> getAntragstellerMap(Map<String, Object> formDataMap) { + private Optional<LinkedHashMap<String, Object>> getAntragstellerMap(Map<String, Object> formDataMap) { return Optional.ofNullable(formDataMap.get(ANTRAGSTELLER)) .or(() -> Optional.ofNullable(formDataMap.get(ANTRAGSTELLER_UPPERCASE))) - .map(Map.class::cast).map(LinkedHashMap::new); + .map(Map.class::cast) + .map(LinkedHashMap<String, Object>::new); } private Antragsteller.AntragstellerBuilder addAntragstellerData(Antragsteller.AntragstellerBuilder builder, @@ -125,4 +125,4 @@ class AfmAntragstellerMapper implements AfmEngineBasedMapper { } return Collections.unmodifiableMap(editableMap); } -} \ No newline at end of file +} diff --git a/semantik-adapter/src/main/java/de/ozgcloud/eingang/semantik/enginebased/afm/AfmEngineBasedAdapter.java b/semantik-adapter/src/main/java/de/ozgcloud/eingang/semantik/enginebased/afm/AfmEngineBasedAdapter.java index 739ef9e7c9fe38bdede62e9812ec9a98821f7297..8f6733cd1d89b68580e8ab128fae413714b87e61 100644 --- a/semantik-adapter/src/main/java/de/ozgcloud/eingang/semantik/enginebased/afm/AfmEngineBasedAdapter.java +++ b/semantik-adapter/src/main/java/de/ozgcloud/eingang/semantik/enginebased/afm/AfmEngineBasedAdapter.java @@ -26,30 +26,52 @@ package de.ozgcloud.eingang.semantik.enginebased.afm; import java.util.List; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; import de.ozgcloud.eingang.common.formdata.FormData; import de.ozgcloud.eingang.common.formdata.FormDataUtils; import de.ozgcloud.eingang.semantik.enginebased.EngineBasedSemantikAdapter; +import de.ozgcloud.eingang.semantik.enginebased.afm.intelliform.IntelliFormRepresentationAdapter; +import lombok.RequiredArgsConstructor; +@Component public class AfmEngineBasedAdapter implements EngineBasedSemantikAdapter { + @Autowired + private IntelliFormRepresentationAdapter intelliFormRepresentationAdapter; + @Autowired private List<AfmEngineBasedMapper> mappers; @Override public FormData parseFormData(FormData formData) { - var processedFormData = formData; + var vorgangNummer = formData.getHeader().getVorgangNummer(); + var processedFormData = intelliFormRepresentationAdapter.adaptByRepresentations(formData); for (var mapper : mappers) { processedFormData = mapper.parseFormData(processedFormData); } - return removeProcessedData(processedFormData); + return removeProcessedData(addVorgangNummer(processedFormData, vorgangNummer)); + } + + private FormData addVorgangNummer(FormData formData, String vorgangNummer) { + return formData.toBuilder() + .header(formData.getHeader().toBuilder() + .vorgangNummer(vorgangNummer) + .build() + ) + .build(); } - FormData removeProcessedData(FormData formData) { + private FormData removeProcessedData(FormData formData) { return FormDataUtils.from(formData) .remove(AfmAntragstellerMapper.POSTFACH_ID) .build(); } -} \ No newline at end of file + + @Override + public boolean isResponsible(FormData formData) { + return intelliFormRepresentationAdapter.isResponsible(formData); + } +} diff --git a/semantik-adapter/src/main/java/de/ozgcloud/eingang/semantik/enginebased/afm/AfmAttachedFilesMapper.java b/semantik-adapter/src/main/java/de/ozgcloud/eingang/semantik/enginebased/afm/AfmFileCountMapper.java similarity index 68% rename from semantik-adapter/src/main/java/de/ozgcloud/eingang/semantik/enginebased/afm/AfmAttachedFilesMapper.java rename to semantik-adapter/src/main/java/de/ozgcloud/eingang/semantik/enginebased/afm/AfmFileCountMapper.java index 6daeceab9dfd7e9f397b46fa087792ae4dff7560..e706d63e31d8161b639826fe9f22b06beeda65d1 100644 --- a/semantik-adapter/src/main/java/de/ozgcloud/eingang/semantik/enginebased/afm/AfmAttachedFilesMapper.java +++ b/semantik-adapter/src/main/java/de/ozgcloud/eingang/semantik/enginebased/afm/AfmFileCountMapper.java @@ -29,19 +29,14 @@ import de.ozgcloud.eingang.common.formdata.FormData; import de.ozgcloud.eingang.semantik.enginebased.FilesMapperHelper; @Component -class AfmAttachedFilesMapper implements AfmEngineBasedMapper { +class AfmFileCountMapper implements AfmEngineBasedMapper { @Override public FormData parseFormData(FormData formData) { - var formDataBuilder = formData.toBuilder(); - FilesMapperHelper.getAttachedFileGroups(formData) - .ifPresent(fileGroups -> formDataBuilder - .attachments(fileGroups) - .numberOfAttachments(FilesMapperHelper.countAttachedFiles(fileGroups))); - FilesMapperHelper.getRepresentations(formData) - .ifPresent(representations -> formDataBuilder.representations(representations).numberOfRepresentations(representations.size())); - - return FilesMapperHelper.removeProcessedData(formDataBuilder.build()); + return formData.toBuilder() + .numberOfRepresentations(formData.getRepresentations().size()) + .numberOfAttachments(FilesMapperHelper.countAttachedFiles(formData.getAttachments())) + .build(); } -} \ No newline at end of file +} diff --git a/semantik-adapter/src/main/java/de/ozgcloud/eingang/semantik/enginebased/afm/intelliform/IntelliFormRepresentationAdapter.java b/semantik-adapter/src/main/java/de/ozgcloud/eingang/semantik/enginebased/afm/intelliform/IntelliFormRepresentationAdapter.java new file mode 100644 index 0000000000000000000000000000000000000000..36fb9fa6507228103bb71f8c0d2612d39b868c11 --- /dev/null +++ b/semantik-adapter/src/main/java/de/ozgcloud/eingang/semantik/enginebased/afm/intelliform/IntelliFormRepresentationAdapter.java @@ -0,0 +1,143 @@ +package de.ozgcloud.eingang.semantik.enginebased.afm.intelliform; + +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.Set; +import java.util.stream.Collector; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import org.apache.commons.collections.MapUtils; +import org.springframework.stereotype.Component; +import org.w3c.dom.Document; + +import de.ozgcloud.eingang.common.errorhandling.TechnicalException; +import de.ozgcloud.eingang.common.formdata.FormData; +import de.ozgcloud.eingang.common.formdata.IncomingFile; +import de.ozgcloud.eingang.common.formdata.IncomingFileGroup; +import lombok.RequiredArgsConstructor; +import lombok.extern.log4j.Log4j2; + +@Component +@RequiredArgsConstructor +@Log4j2 +public class IntelliFormRepresentationAdapter { + + static final String INTELLIFORM_TYPENAME = "http://xmlns.cit.de/intelliform/transaction"; + + static final String FILE = "file"; + + static final String HEADER_FIELD = "header"; + + public static final List<String> HEADER_ATTRIBUTE_NAMES = List.of( + "t:id", + "t:timestamp", + "t:form-id", + "t:form", + "t:sender", + "t:customer", + "t:customer-id", + "t:client", + "t:client-id" + ); + public static final List<String> CUSTOM_HEADER_ATTRIBUTE_NAMES = List.of( + "u:saml_legacypostkorbhandle", + "u:saml_givenname", + "u:saml_surname", + "u:saml_placeofbirth", + "u:saml_birthname", + "u:saml_mail", + "u:saml_telephonenumber", + "u:saml_postaladdress", + "u:saml_postalcode", + "u:saml_localityname" + ); + + private static final Collector<Map.Entry<String, ?>, ?, Map<String, Object>> ORDERED_MAP_ENTRY_COLLECTOR = Collectors.toMap( + Map.Entry::getKey, + Map.Entry::getValue, + (u, v) -> v, + LinkedHashMap::new + ); + + private final XmlToJavaMapsMapper xmlToJavaMapsMapper; + + public boolean isResponsible(FormData formData) { + return findIntelliFormXMLRepresentation(formData) + .isPresent(); + } + + Optional<Document> findIntelliFormXMLRepresentation(FormData formData) { + return streamXMLDocumentsFromRepresentations(formData) + .filter(document -> { + var element = document.getDocumentElement(); + var attribute = element.getAttribute("xmlns:t"); + return attribute.equals(INTELLIFORM_TYPENAME); + }) + .findFirst(); + } + + Stream<Document> streamXMLDocumentsFromRepresentations(FormData formData) { + return formData.getRepresentations().stream() + .filter(representation -> representation.getContentType().contains("xml")) + .flatMap(xmlRepresentation -> { + try { + return Stream.of(xmlToJavaMapsMapper.parseAsW3cDocument(xmlRepresentation.getContentStream())); + } catch (TechnicalException exception) { + return Stream.empty(); + } + }); + } + + public FormData adaptByRepresentations(FormData formData) { + var document = findIntelliFormXMLRepresentation(formData) + .orElseThrow(() -> new TechnicalException("Expect to find IntelliForm XML representation!")); + + return FormData.builder() + .representations(formData.getRepresentations()) + .attachments(formData.getAttachments()) + .formData(Stream.concat( + getFormDataEntriesFromDocument(document, formData.getAttachments()), + Map.of( + HEADER_FIELD, createHeaderMap(document) + ).entrySet().stream() + ).collect(ORDERED_MAP_ENTRY_COLLECTOR)) + .build(); + } + + Stream<Map.Entry<String, Object>> getFormDataEntriesFromDocument(Document document, List<IncomingFileGroup> attachments) { + Set<String> attachmentVendorIds = attachments.stream() + .flatMap(group -> group.getFiles().stream()) + .map(IncomingFile::getVendorId) + .collect(Collectors.toSet()); + + return xmlToJavaMapsMapper.mapXmlToJavaMaps(document).entrySet() + .stream() + .filter(entry -> !isUploadElementWhichRefersToAttachment(entry.getValue(), attachmentVendorIds)); + } + + private boolean isUploadElementWhichRefersToAttachment(Object element, Set<String> attachmentVendorIds) { + return findVendorIdInUploadElementCandidate(element) + .map(attachmentVendorIds::contains) + .orElse(false); + } + + @SuppressWarnings("rawtypes") + private Optional<String> findVendorIdInUploadElementCandidate(Object element) { + if (element instanceof Map uploadElement) { + return Optional.ofNullable(MapUtils.getMap(uploadElement, FILE)) + .flatMap(fileElement -> Optional.ofNullable(MapUtils.getString(fileElement, "id"))); + } else { + return Optional.empty(); + } + } + + Map<String, Object> createHeaderMap(Document document) { + var element = document.getDocumentElement(); + return Stream.concat(HEADER_ATTRIBUTE_NAMES.stream(), CUSTOM_HEADER_ATTRIBUTE_NAMES.stream().filter(element::hasAttribute)) + .collect(Collectors.toMap(name -> name, element::getAttribute)); + } + +} diff --git a/intelliform-adapter/src/main/java/de/ozgcloud/eingang/intelliform/JsonService.java b/semantik-adapter/src/main/java/de/ozgcloud/eingang/semantik/enginebased/afm/intelliform/JsonService.java similarity index 93% rename from intelliform-adapter/src/main/java/de/ozgcloud/eingang/intelliform/JsonService.java rename to semantik-adapter/src/main/java/de/ozgcloud/eingang/semantik/enginebased/afm/intelliform/JsonService.java index fa8c516f641b18f518ec3d19323a01d81a7287c4..04d21f1a271da454917f3a580727e31bc3baac98 100644 --- a/intelliform-adapter/src/main/java/de/ozgcloud/eingang/intelliform/JsonService.java +++ b/semantik-adapter/src/main/java/de/ozgcloud/eingang/semantik/enginebased/afm/intelliform/JsonService.java @@ -1,4 +1,4 @@ -package de.ozgcloud.eingang.intelliform; +package de.ozgcloud.eingang.semantik.enginebased.afm.intelliform; import java.util.List; import java.util.Map; @@ -32,4 +32,4 @@ class JsonService { throw new TechnicalException("Error parsing JSON", e); } } -} \ No newline at end of file +} diff --git a/intelliform-adapter/src/main/java/de/ozgcloud/eingang/intelliform/XmlToJavaMapsMapper.java b/semantik-adapter/src/main/java/de/ozgcloud/eingang/semantik/enginebased/afm/intelliform/XmlToJavaMapsMapper.java similarity index 98% rename from intelliform-adapter/src/main/java/de/ozgcloud/eingang/intelliform/XmlToJavaMapsMapper.java rename to semantik-adapter/src/main/java/de/ozgcloud/eingang/semantik/enginebased/afm/intelliform/XmlToJavaMapsMapper.java index bd7164616db3a639cfe66538da9beafd303aaabf..75409a60e28a1966f85e4b1caa4ecdda90fa569e 100644 --- a/intelliform-adapter/src/main/java/de/ozgcloud/eingang/intelliform/XmlToJavaMapsMapper.java +++ b/semantik-adapter/src/main/java/de/ozgcloud/eingang/semantik/enginebased/afm/intelliform/XmlToJavaMapsMapper.java @@ -21,7 +21,7 @@ * Die sprachspezifischen Genehmigungen und Beschränkungen * unter der Lizenz sind dem Lizenztext zu entnehmen. */ -package de.ozgcloud.eingang.intelliform; +package de.ozgcloud.eingang.semantik.enginebased.afm.intelliform; import java.io.IOException; import java.io.InputStream; @@ -184,4 +184,4 @@ class XmlToJavaMapsMapper { return Collections.emptyList(); } } -} \ No newline at end of file +} diff --git a/semantik-adapter/src/main/java/de/ozgcloud/eingang/semantik/formbased/DFoerdermittelFormBasedMapper.java b/semantik-adapter/src/main/java/de/ozgcloud/eingang/semantik/enginebased/dfoerdermittel/DFoerdermittelEngineBasedSemantikAdapter.java similarity index 82% rename from semantik-adapter/src/main/java/de/ozgcloud/eingang/semantik/formbased/DFoerdermittelFormBasedMapper.java rename to semantik-adapter/src/main/java/de/ozgcloud/eingang/semantik/enginebased/dfoerdermittel/DFoerdermittelEngineBasedSemantikAdapter.java index 6c2292d48b4b596feef5e0abdc3d087099a94d9d..1bb43a80e2f70556be226637d2d63ad78de41efe 100644 --- a/semantik-adapter/src/main/java/de/ozgcloud/eingang/semantik/formbased/DFoerdermittelFormBasedMapper.java +++ b/semantik-adapter/src/main/java/de/ozgcloud/eingang/semantik/enginebased/dfoerdermittel/DFoerdermittelEngineBasedSemantikAdapter.java @@ -1,4 +1,4 @@ -package de.ozgcloud.eingang.semantik.formbased; +package de.ozgcloud.eingang.semantik.enginebased.dfoerdermittel; import java.io.IOException; import java.io.InputStream; @@ -20,13 +20,15 @@ import de.ozgcloud.eingang.common.formdata.FormData; import de.ozgcloud.eingang.common.formdata.IncomingFile; import de.ozgcloud.eingang.common.formdata.ServiceKonto; import de.ozgcloud.eingang.common.formdata.ZustaendigeStelle; +import de.ozgcloud.eingang.semantik.enginebased.EngineBasedSemantikAdapter; import de.ozgcloud.eingang.semantik.enginebased.ServiceKontoBuildHelper; import lombok.NonNull; +import lombok.RequiredArgsConstructor; import lombok.extern.log4j.Log4j2; @Log4j2 @Component -public class DFoerdermittelFormBasedMapper implements FormBasedMapper { +public class DFoerdermittelEngineBasedSemantikAdapter implements EngineBasedSemantikAdapter { private static final String FACHNACHRICHT_SUFFIX = "Fachnachricht.xml"; private static final Predicate<IncomingFile> IS_FACHNACHRICHT = inFile -> StringUtils.endsWith(inFile.getName(), FACHNACHRICHT_SUFFIX); @@ -51,7 +53,9 @@ public class DFoerdermittelFormBasedMapper implements FormBasedMapper { Map<String, Object> fachnachricht = (Map<String, Object>) MapUtils.getMap(formData.getFormData(), KEY_FACHNACHRICHT, Collections.<String, Object>emptyMap()); - var extendedFormData = addServiceKonto(formData, fachnachricht); + var extendedFormData = addFormName(formData); + extendedFormData = addFormEngineName(extendedFormData); + extendedFormData = addServiceKonto(extendedFormData, fachnachricht); return addOrganisationsEinheitId(extendedFormData, fachnachricht); } @@ -82,6 +86,25 @@ public class DFoerdermittelFormBasedMapper implements FormBasedMapper { return zustaendigeStelleBuilder.organisationseinheitenId(orgaId).build(); } + FormData addFormName(FormData formData) { + return formData.toBuilder() + .header(formData.getHeader().toBuilder() + // TODO replace formName with actual name <Title> from Fachnachricht (KOP-2239) + .formName("dFördermittelantrag") + .build() + ) + .build(); + } + + FormData addFormEngineName(FormData formData) { + return formData.toBuilder() + .header(formData.getHeader().toBuilder() + .formEngineName("dFördermittelantrag") + .build() + ) + .build(); + } + String extractPrefix(@NonNull String postfachId) { return postfachId.substring(postfachId.lastIndexOf("/") + 1); } diff --git a/semantik-adapter/src/main/java/de/ozgcloud/eingang/semantik/enginebased/formsolutions/FormSolutionsFilesMapper.java b/semantik-adapter/src/main/java/de/ozgcloud/eingang/semantik/enginebased/formsolutions/FormSolutionsFilesMapper.java index f4e91092747456556d75874ee1a8cddc12c5dfc2..d63b1e4f5a502a5efce7f280b107422e0ee83a64 100644 --- a/semantik-adapter/src/main/java/de/ozgcloud/eingang/semantik/enginebased/formsolutions/FormSolutionsFilesMapper.java +++ b/semantik-adapter/src/main/java/de/ozgcloud/eingang/semantik/enginebased/formsolutions/FormSolutionsFilesMapper.java @@ -33,7 +33,7 @@ import org.springframework.stereotype.Component; import de.ozgcloud.eingang.common.formdata.FormData; import de.ozgcloud.eingang.common.formdata.IncomingFile; import de.ozgcloud.eingang.common.formdata.IncomingFileGroup; -import de.ozgcloud.eingang.semantik.common.ZipAttachmentReader; +import de.ozgcloud.eingang.common.zip.ZipAttachmentReader; import de.ozgcloud.eingang.semantik.enginebased.FilesMapperHelper; import lombok.RequiredArgsConstructor; import lombok.extern.log4j.Log4j2; diff --git a/semantik-adapter/src/main/java/de/ozgcloud/eingang/semantik/enginebased/xta/XtaEngineBasedAdapter.java b/semantik-adapter/src/main/java/de/ozgcloud/eingang/semantik/enginebased/xta/XtaEngineBasedAdapter.java deleted file mode 100644 index a74ff267bd5984e068abd0fc00a9bd6c2469e05d..0000000000000000000000000000000000000000 --- a/semantik-adapter/src/main/java/de/ozgcloud/eingang/semantik/enginebased/xta/XtaEngineBasedAdapter.java +++ /dev/null @@ -1,26 +0,0 @@ -package de.ozgcloud.eingang.semantik.enginebased.xta; - -import java.util.List; - -import org.springframework.beans.factory.annotation.Autowired; - -import de.ozgcloud.eingang.common.formdata.FormData; -import de.ozgcloud.eingang.semantik.enginebased.EngineBasedSemantikAdapter; - -public class XtaEngineBasedAdapter implements EngineBasedSemantikAdapter { - - @Autowired - private List<XtaEngineBasedMapper> mappers; - - @Override - public FormData parseFormData(FormData formData) { - var processed = formData; - - for (var mapper : mappers) { - processed = mapper.parseFormData(processed); - } - - return processed; - } - -} diff --git a/semantik-adapter/src/main/java/de/ozgcloud/eingang/semantik/enginebased/xta/XtaEngineBasedMapper.java b/semantik-adapter/src/main/java/de/ozgcloud/eingang/semantik/enginebased/xta/XtaEngineBasedMapper.java deleted file mode 100644 index 085f7f230d0b65cd06215654e1554c31cce7baeb..0000000000000000000000000000000000000000 --- a/semantik-adapter/src/main/java/de/ozgcloud/eingang/semantik/enginebased/xta/XtaEngineBasedMapper.java +++ /dev/null @@ -1,7 +0,0 @@ -package de.ozgcloud.eingang.semantik.enginebased.xta; - -import de.ozgcloud.eingang.semantik.enginebased.EngineBasedMapper; - -public interface XtaEngineBasedMapper extends EngineBasedMapper { - -} diff --git a/semantik-adapter/src/main/java/de/ozgcloud/eingang/semantik/enginebased/xta/XtaZipRepresentationsMapper.java b/semantik-adapter/src/main/java/de/ozgcloud/eingang/semantik/enginebased/xta/XtaZipRepresentationsMapper.java deleted file mode 100644 index 9a0814f1efa9b86843d27db360a53986091b2dd2..0000000000000000000000000000000000000000 --- a/semantik-adapter/src/main/java/de/ozgcloud/eingang/semantik/enginebased/xta/XtaZipRepresentationsMapper.java +++ /dev/null @@ -1,45 +0,0 @@ -package de.ozgcloud.eingang.semantik.enginebased.xta; - -import java.util.Collections; -import java.util.List; -import java.util.function.Predicate; - -import org.springframework.stereotype.Component; - -import de.ozgcloud.eingang.common.formdata.FormData; -import de.ozgcloud.eingang.common.formdata.IncomingFile; -import de.ozgcloud.eingang.semantik.common.ZipAttachmentReader; -import lombok.extern.log4j.Log4j2; - -@Component -@Log4j2 -public class XtaZipRepresentationsMapper implements XtaEngineBasedMapper { - - public static final String ZIP_CONTENT_TYPE = "application/zip"; - - static final Predicate<IncomingFile> IS_ZIP_FILE = contentType -> ZIP_CONTENT_TYPE.equals(contentType.getContentType()); - - @Override - public FormData parseFormData(FormData srcFormData) { - - List<IncomingFile> extractedFiles = srcFormData.getRepresentations().stream() - .filter(IS_ZIP_FILE) - .map(this::extractZip) - .flatMap(List::stream) - .toList(); - - return srcFormData - .toBuilder() - .representations(extractedFiles) - .numberOfRepresentations(srcFormData.getNumberOfRepresentations() + extractedFiles.size()).build(); - } - - List<IncomingFile> extractZip(IncomingFile zipFile) { - try { - return ZipAttachmentReader.from(zipFile.getContentStream(), zipFile.getName()).readContent(); - } catch (RuntimeException e) { - LOG.error("Cannot read source ZIP. Not extracting file", e); - return Collections.emptyList(); - } - } -} diff --git a/semantik-adapter/src/main/java/de/ozgcloud/eingang/semantik/formbased/AnliegenId.java b/semantik-adapter/src/main/java/de/ozgcloud/eingang/semantik/formbased/AnliegenId.java deleted file mode 100644 index 7ae3363c94933a5ea0f5b1a73ddcdacf5ddc22b7..0000000000000000000000000000000000000000 --- a/semantik-adapter/src/main/java/de/ozgcloud/eingang/semantik/formbased/AnliegenId.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright (C) 2022 Das Land Schleswig-Holstein vertreten durch den - * Ministerpräsidenten des Landes Schleswig-Holstein - * Staatskanzlei - * Abteilung Digitalisierung und zentrales IT-Management der Landesregierung - * - * Lizenziert unter der EUPL, Version 1.2 oder - sobald - * diese von der Europäischen Kommission genehmigt wurden - - * Folgeversionen der EUPL ("Lizenz"); - * Sie dürfen dieses Werk ausschließlich gemäß - * dieser Lizenz nutzen. - * Eine Kopie der Lizenz finden Sie hier: - * - * https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 - * - * Sofern nicht durch anwendbare Rechtsvorschriften - * gefordert oder in schriftlicher Form vereinbart, wird - * die unter der Lizenz verbreitete Software "so wie sie - * ist", OHNE JEGLICHE GEWÄHRLEISTUNG ODER BEDINGUNGEN - - * ausdrücklich oder stillschweigend - verbreitet. - * Die sprachspezifischen Genehmigungen und Beschränkungen - * unter der Lizenz sind dem Lizenztext zu entnehmen. - */ -package de.ozgcloud.eingang.semantik.formbased; - -import de.ozgcloud.common.datatype.StringBasedValue; - -class AnliegenId extends StringBasedValue { - - private static final long serialVersionUID = 1L; - - AnliegenId(String anliegenId) { - super(anliegenId); - } - - public static AnliegenId from(String anliegenId) { - return new AnliegenId(anliegenId); - } -} \ No newline at end of file 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 98b3e7fc66f6f4a1ccd849a07c68cc0e6eed9755..dbe206cafc115bf08a30839bab78afbc1933fdb3 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,25 +23,36 @@ */ package de.ozgcloud.eingang.semantik; +import static org.assertj.core.api.Assertions.*; 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; +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 de.ozgcloud.eingang.common.formdata.FormData; import de.ozgcloud.eingang.router.VorgangService; -import de.ozgcloud.eingang.semantik.SemantikAdapter; import de.ozgcloud.eingang.semantik.enginebased.EngineBasedSemantikAdapter; import de.ozgcloud.eingang.semantik.formbased.FormBasedSemantikAdapter; class SemantikAdapterTest { + @Spy @InjectMocks private SemantikAdapter adapter; + + @Mock + private List<EngineBasedSemantikAdapter> engineAdapters; + @Mock private EngineBasedSemantikAdapter engineAdapter; @Mock @@ -49,6 +60,39 @@ class SemantikAdapterTest { @Mock private VorgangService vorgangService; + @DisplayName("find responsible engine adapter") + @Nested + class TestFindResponsibleEngineAdapter { + + @BeforeEach + void mock() { + when(engineAdapters.stream()).thenReturn(Stream.of(engineAdapter)); + } + + @Mock + private FormData formData; + + @DisplayName("should return responsible") + @Test + void shouldReturnResponsible() { + when(engineAdapter.isResponsible(any())).thenReturn(true); + + var foundAdapter = adapter.findResponsibleEngineAdapter(formData); + + assertThat(foundAdapter).isEqualTo(Optional.of(engineAdapter)); + } + + @DisplayName("should return empty if not responsible") + @Test + void shouldReturnEmptyIfNotResponsible() { + when(engineAdapter.isResponsible(any())).thenReturn(false); + + var foundAdapter = adapter.findResponsibleEngineAdapter(formData); + + assertThat(foundAdapter).isNotPresent(); + } + } + @Nested class TestProcessFormData { @@ -61,10 +105,18 @@ class SemantikAdapterTest { @BeforeEach void mockEngineAdapter() { + doReturn(Optional.of(engineAdapter)).when(adapter).findResponsibleEngineAdapter(formData); when(engineAdapter.parseFormData(any())).thenReturn(engineAdapterResponse); when(formAdapter.parseFormData(any())).thenReturn(formAdapterResponse); } + @Test + void shouldCallFindEngineAdapter() { + adapter.processFormData(formData); + + verify(adapter).findResponsibleEngineAdapter(formData); + } + @Test void shouldCallEngineAdapter() { adapter.processFormData(formData); @@ -86,4 +138,4 @@ class SemantikAdapterTest { verify(vorgangService).createVorgang(formAdapterResponse); } } -} \ No newline at end of file +} diff --git a/semantik-adapter/src/test/java/de/ozgcloud/eingang/semantik/enginebased/afm/AfmEngineBasedAdapterTest.java b/semantik-adapter/src/test/java/de/ozgcloud/eingang/semantik/enginebased/afm/AfmEngineBasedAdapterTest.java index ff4575a298712beaa7bdc0e8cbe035e83b9c714e..609284d26fccdb41ed91818c5df7ed0161990cdc 100644 --- a/semantik-adapter/src/test/java/de/ozgcloud/eingang/semantik/enginebased/afm/AfmEngineBasedAdapterTest.java +++ b/semantik-adapter/src/test/java/de/ozgcloud/eingang/semantik/enginebased/afm/AfmEngineBasedAdapterTest.java @@ -24,11 +24,9 @@ package de.ozgcloud.eingang.semantik.enginebased.afm; import static org.assertj.core.api.Assertions.*; -import static org.mockito.ArgumentMatchers.*; import static org.mockito.Mockito.*; import java.util.Collections; -import java.util.List; import java.util.Map; import org.junit.jupiter.api.BeforeEach; @@ -41,50 +39,58 @@ import org.mockito.Spy; import org.springframework.test.util.ReflectionTestUtils; import de.ozgcloud.eingang.common.formdata.FormData; -import de.ozgcloud.eingang.semantik.enginebased.EngineBasedMapper; -import de.ozgcloud.eingang.semantik.enginebased.afm.AfmAntragstellerMapper; -import de.ozgcloud.eingang.semantik.enginebased.afm.AfmEngineBasedAdapter; -import de.ozgcloud.eingang.semantik.enginebased.afm.AfmEngineBasedMapper; +import de.ozgcloud.eingang.common.formdata.FormHeader; +import de.ozgcloud.eingang.semantik.enginebased.afm.intelliform.IntelliFormRepresentationAdapter; class AfmEngineBasedAdapterTest { @Spy @InjectMocks private AfmEngineBasedAdapter adapter; - @Spy - private List<EngineBasedMapper> mappers; @Mock private AfmEngineBasedMapper mapper; + @Mock + private IntelliFormRepresentationAdapter intelliFormRepresentationAdapters; + @DisplayName("Parse form data") @Nested class TestParseFromData { + private final String VORGANG_NUMMER = "AAAA-1234"; private final Map<String, Object> formDataMap = Map.of(AfmAntragstellerMapper.POSTFACH_ID, "postfachIdValue"); - private final FormData formData = FormData.builder().formData(formDataMap).build(); + private final FormData formData = FormData.builder() + .header(FormHeader.builder() + .vorgangNummer(VORGANG_NUMMER) + .build() + ) + .formData(formDataMap) + .build(); + + private final FormData processedFormData = FormData.builder() + .formData(formDataMap) + .build(); @BeforeEach - void mockMappers() { + void mock() { ReflectionTestUtils.setField(adapter, "mappers", Collections.singletonList(mapper)); - } - @BeforeEach - void mockEngineBasedMapper() { - when(mapper.parseFormData(any())).thenReturn(formData); + when(mapper.parseFormData(processedFormData)).thenReturn(processedFormData); + when(intelliFormRepresentationAdapters.adaptByRepresentations(formData)).thenReturn(processedFormData); } @Test - void shouldCallMappers() { + void shouldCallRepresentationAdapter() { adapter.parseFormData(formData); - verify(mapper).parseFormData(formData); + verify(intelliFormRepresentationAdapters).adaptByRepresentations(formData); } @Test - void shouldRemoveProcessedData() { + void shouldCallMappers() { adapter.parseFormData(formData); - verify(adapter).removeProcessedData(formData); + verify(mapper).parseFormData(processedFormData); } @Test @@ -93,5 +99,14 @@ class AfmEngineBasedAdapterTest { assertThat(mappedFormData.getFormData()).doesNotContainKey(AfmAntragstellerMapper.POSTFACH_ID); } + + @DisplayName("should keep vorgang nummer") + @Test + void shouldKeepVorgangNummer() { + var mappedFormData = adapter.parseFormData(formData); + + assertThat(mappedFormData.getHeader().getVorgangNummer()).isEqualTo(VORGANG_NUMMER); + } } + } diff --git a/semantik-adapter/src/test/java/de/ozgcloud/eingang/semantik/enginebased/afm/AfmAttachedFilesMapperTest.java b/semantik-adapter/src/test/java/de/ozgcloud/eingang/semantik/enginebased/afm/AfmFileCountMapperTest.java similarity index 75% rename from semantik-adapter/src/test/java/de/ozgcloud/eingang/semantik/enginebased/afm/AfmAttachedFilesMapperTest.java rename to semantik-adapter/src/test/java/de/ozgcloud/eingang/semantik/enginebased/afm/AfmFileCountMapperTest.java index 2643740ae163291151e0573b6b9537514ce0b831..7c63ef8ed048579653880f4ef7904f0b97d9554a 100644 --- a/semantik-adapter/src/test/java/de/ozgcloud/eingang/semantik/enginebased/afm/AfmAttachedFilesMapperTest.java +++ b/semantik-adapter/src/test/java/de/ozgcloud/eingang/semantik/enginebased/afm/AfmFileCountMapperTest.java @@ -26,44 +26,40 @@ package de.ozgcloud.eingang.semantik.enginebased.afm; import static org.assertj.core.api.Assertions.*; import java.util.List; -import java.util.Map; import de.ozgcloud.eingang.common.formdata.FormData; import de.ozgcloud.eingang.common.formdata.FormDataTestFactory; import de.ozgcloud.eingang.common.formdata.IncomingFileGroup; import de.ozgcloud.eingang.common.formdata.IncomingFileGroupTestFactory; import de.ozgcloud.eingang.common.formdata.IncomingFileTestFactory; -import de.ozgcloud.eingang.semantik.enginebased.FilesMapperHelper; -import de.ozgcloud.eingang.semantik.enginebased.afm.AfmAttachedFilesMapper; import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; import org.mockito.InjectMocks; import org.mockito.Spy; -class AfmAttachedFilesMapperTest { +class AfmFileCountMapperTest { @Spy @InjectMocks - private AfmAttachedFilesMapper mapper; + private AfmFileCountMapper mapper; - private IncomingFileGroup attachmentWithMultipleFiles = IncomingFileGroupTestFactory.createBuilder() + private final IncomingFileGroup attachmentWithMultipleFiles = IncomingFileGroupTestFactory.createBuilder() .name("anotherAttachment") .clearFiles() .files(List.of(IncomingFileTestFactory.create(), IncomingFileTestFactory.create())) .build(); - private FormData formData = FormDataTestFactory.createBuilder() + private final FormData formData = FormDataTestFactory.createBuilder() .clearAttachments() - .formData(Map.of(FilesMapperHelper.FIELD_NAME_MAPPED_FILES, - Map.of(FilesMapperHelper.ATTACHMENTS, List.of(IncomingFileGroupTestFactory.create(), attachmentWithMultipleFiles)))) + .attachments(List.of(IncomingFileGroupTestFactory.create(), attachmentWithMultipleFiles)) .build(); @Nested class TestParseFormData { @Test - void shouldMapAttachments() { + void shouldKeepAttachments() { var parsedFormData = parseFormData(); assertThat(parsedFormData.getAttachments()).hasSize(2); @@ -79,7 +75,7 @@ class AfmAttachedFilesMapperTest { } @Test - void shouldMapRepresentations() { + void shouldKeepRepresentations() { var parsedFormData = parseFormData(); assertThat(parsedFormData.getRepresentations()).hasSize(1); @@ -92,15 +88,8 @@ class AfmAttachedFilesMapperTest { assertThat(parsedFormData.getNumberOfRepresentations()).isEqualTo(1); } - @Test - void shouldRemoveFilesFromMap() { - var parsedFormData = parseFormData(); - - assertThat(parsedFormData.getFormData().get(FilesMapperHelper.FIELD_NAME_MAPPED_FILES)).isNull(); - } - private FormData parseFormData() { return mapper.parseFormData(formData); } } -} \ No newline at end of file +} diff --git a/semantik-adapter/src/test/java/de/ozgcloud/eingang/semantik/enginebased/afm/intelliform/IntelliFormRepresentationAdapterTest.java b/semantik-adapter/src/test/java/de/ozgcloud/eingang/semantik/enginebased/afm/intelliform/IntelliFormRepresentationAdapterTest.java new file mode 100644 index 0000000000000000000000000000000000000000..27be6b86a22cc6658bb7421265e3b914fb990817 --- /dev/null +++ b/semantik-adapter/src/test/java/de/ozgcloud/eingang/semantik/enginebased/afm/intelliform/IntelliFormRepresentationAdapterTest.java @@ -0,0 +1,456 @@ +package de.ozgcloud.eingang.semantik.enginebased.afm.intelliform; + +import static de.ozgcloud.eingang.semantik.enginebased.afm.intelliform.IntelliFormRepresentationAdapter.*; +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.io.InputStream; +import java.io.StringReader; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.ParserConfigurationException; + +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.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.Spy; +import org.w3c.dom.Document; +import org.xml.sax.InputSource; +import org.xml.sax.SAXException; + +import com.thedeanda.lorem.LoremIpsum; + +import de.ozgcloud.eingang.common.errorhandling.TechnicalException; +import de.ozgcloud.eingang.common.formdata.FormData; +import de.ozgcloud.eingang.common.formdata.IncomingFile; +import de.ozgcloud.eingang.common.formdata.IncomingFileGroup; +import de.ozgcloud.eingang.common.formdata.IncomingFileGroupTestFactory; +import de.ozgcloud.eingang.common.formdata.IncomingFileTestFactory; + +class IntelliFormRepresentationAdapterTest { + + private static final String DOCUMENT_TEST_KEY = "doc-test-key"; + private static final String DOCUMENT_TEST_VALUE = "doc-test-value"; + + @Spy + @InjectMocks + IntelliFormRepresentationAdapter adapter; + + @Mock + private XmlToJavaMapsMapper xmlToJavaMapsMapper; + + @DisplayName("find IntelliForm XML representation") + @Nested + class TestFindIntelliFormXmlRepresentation { + + @Mock + private FormData formData; + + @DisplayName("should find first with IntelliForm schema") + @Test + void shouldFindFirstWithIntelliFormSchema() { + var schemas = Stream.of( + "<root xmlns=\"%s\" />".formatted(INTELLIFORM_TYPENAME), + "<root xmlns:t=\"unknown\">first</root>", + "<root>second</root>", + "<root xmlns:t=\"%s\">third</root>".formatted(INTELLIFORM_TYPENAME), + "<root xmlns:t=\"%s\">fourth</root>".formatted(INTELLIFORM_TYPENAME) + ).map(IntelliFormRepresentationAdapterTest.this::buildXMLDocument); + doReturn(schemas).when(adapter).streamXMLDocumentsFromRepresentations(formData); + + var firstWithSchema = adapter.findIntelliFormXMLRepresentation(formData); + + assertThat(firstWithSchema).isPresent(); + var rootElement = firstWithSchema.get().getDocumentElement(); + assertThat(rootElement.getTextContent()).isEqualTo("third"); + } + } + + @DisplayName("stream XML documents from representations") + @Nested + class TestStreamXmlDocumentsFromRepresentations { + + @Mock + private Document document; + + @Mock + private FormData formData; + + @Mock + private InputStream inputStream; + + @DisplayName("with no representations") + @Nested + class TestWithNoRepresentations { + @BeforeEach + void mock() { + when(formData.getRepresentations()).thenReturn(Collections.emptyList()); + } + + @DisplayName("should return empty") + @Test + void shouldReturnEmpty() { + var documents = doExtract(); + + assertThat(documents).isEmpty(); + } + } + + @DisplayName("with a xml representation") + @Nested + class TestWithAXMLRepresentations { + @Mock + private IncomingFile otherRepresentation; + + @Mock + private IncomingFile xmlRepresentation; + + @Mock + private IncomingFile otherXMLRepresentation; + + @Mock + private Document otherDocument; + + @Mock + private InputStream otherInputStream; + + @BeforeEach + void mock() { + when(otherRepresentation.getContentType()).thenReturn("pdf"); + when(xmlRepresentation.getContentType()).thenReturn("xml"); + when(otherXMLRepresentation.getContentType()).thenReturn("xml"); + when(formData.getRepresentations()).thenReturn(List.of(otherRepresentation, xmlRepresentation, otherXMLRepresentation)); + + when(xmlRepresentation.getContentStream()).thenReturn(inputStream); + when(xmlToJavaMapsMapper.parseAsW3cDocument(inputStream)).thenReturn(document); + + when(otherXMLRepresentation.getContentStream()).thenReturn(otherInputStream); + + } + + @DisplayName("should include all successfully parsed documents") + @Test + void shouldIncludeAllSuccessfullyParsedDocuments() { + when(xmlToJavaMapsMapper.parseAsW3cDocument(otherInputStream)).thenReturn(otherDocument); + + var documents = doExtract(); + + assertThat(documents).isEqualTo(List.of(document, otherDocument)); + } + + @DisplayName("should skip documents with parse error") + @Test + void shouldSkipDocumentsWithParseError() { + when(xmlToJavaMapsMapper.parseAsW3cDocument(otherInputStream)).thenThrow(new TechnicalException("some error")); + + var documents = doExtract(); + + assertThat(documents).isEqualTo(List.of(document)); + } + } + + private List<Document> doExtract() { + return adapter.streamXMLDocumentsFromRepresentations(formData).toList(); + } + } + + @DisplayName("is responsible") + @Nested + class TestIsResponsible { + + @Mock + private FormData formData; + + @DisplayName("should be true with namespace attribute match") + @Test + void shouldBeTrueWithNamespaceAttributeMatch() { + + doReturn(Optional.of(buildXMLDocument(""" + <myForm xmlns:t="%s"> + </myForm>""".formatted(INTELLIFORM_TYPENAME)))) + .when(adapter).findIntelliFormXMLRepresentation(formData); + + var isResponsible = adapter.isResponsible(formData); + + assertThat(isResponsible).isTrue(); + } + + @DisplayName("should be false without xml document") + @Test + void shouldBeFalseWithoutXmlDocument() { + doReturn(Optional.empty()) + .when(adapter).findIntelliFormXMLRepresentation(formData); + + var isResponsible = adapter.isResponsible(formData); + + assertThat(isResponsible).isFalse(); + } + + } + + @DisplayName("get form data entries from document") + @Nested + class TestGetFormDataEntriesFromDocument { + + private static final String OTHER_VENDOR_ID = "vendorId:other"; + private static final String MISSING_VENDOR_ID = "vendorId:missing"; + + @Mock + private Document document; + + private List<IncomingFileGroup> attachments; + + @BeforeEach + void mock() { + when(xmlToJavaMapsMapper.mapXmlToJavaMaps(document)).thenReturn(Map.of( + DOCUMENT_TEST_KEY, DOCUMENT_TEST_VALUE, + "Upload1", Map.of( + "file", Map.of("id", IncomingFileGroupTestFactory.VENDOR_ID_XXX) + ), + "Upload2", Map.of( + "file", Map.of("id", OTHER_VENDOR_ID) + ), + "Upload3", Map.of( + "file", Map.of("id", "representationId") + ), + "NoUpload1", Map.of( + "file", "" + ), + "NoUpload2", Map.of() + )); + attachments = List.of( + IncomingFileGroupTestFactory.create(), + IncomingFileGroupTestFactory.createBuilder() + .name("other") + .files(List.of( + IncomingFileTestFactory.createBuilder() + .vendorId(MISSING_VENDOR_ID) + .build(), + IncomingFileTestFactory.createBuilder() + .vendorId(OTHER_VENDOR_ID) + .build())) + .build()); + + } + + @DisplayName("should prune upload element if is an attachment") + @Test + void shouldPruneUploadElementIfIsAnAttachment() { + var entryKeys = obtainResidualEntryKeys(); + + assertThat(entryKeys).containsExactlyInAnyOrder(DOCUMENT_TEST_KEY, "Upload3", "NoUpload1", "NoUpload2"); + } + + private List<String> obtainResidualEntryKeys() { + return adapter.getFormDataEntriesFromDocument(document, attachments).map(Map.Entry::getKey).toList(); + } + } + + @DisplayName("create header map") + @Nested + class TestCreateHeaderMap { + + private Document document; + + @DisplayName("with full fields") + @Nested + class TestWithFullFields { + + private Map<String, Object> headerMap; + + @BeforeEach + void mock() { + headerMap = Stream.concat(HEADER_ATTRIBUTE_NAMES.stream(), CUSTOM_HEADER_ATTRIBUTE_NAMES.stream()) + .collect(Collectors.toMap(name -> name, name -> LoremIpsum.getInstance().getName())); + document = buildXMLDocument("<root %s/>".formatted( + headerMap.entrySet().stream() + .map(entry -> "%s=\"%s\"".formatted(entry.getKey(), entry.getValue())) + .collect(Collectors.joining(" ")) + ) + ); + } + + @DisplayName("should include header field") + @ParameterizedTest + @MethodSource("headerNames") + void shouldIncludeAllHeaderField(String headerName) { + var resultHeaderMap = adapter.createHeaderMap(document); + + assertThat(resultHeaderMap).containsEntry(headerName, headerMap.get(headerName)); + } + + private static Stream<Arguments> headerNames() { + return HEADER_ATTRIBUTE_NAMES.stream().map(Arguments::of); + } + + @DisplayName("should include custom header field") + @ParameterizedTest + @MethodSource("customHeaderNames") + void shouldIncludeAllCustomHeaderField(String headerName) { + var resultHeaderMap = adapter.createHeaderMap(document); + + assertThat(resultHeaderMap).containsEntry(headerName, headerMap.get(headerName)); + } + + private static Stream<Arguments> customHeaderNames() { + return CUSTOM_HEADER_ATTRIBUTE_NAMES.stream().map(Arguments::of); + } + } + + @DisplayName("with empty fields") + @Nested + class TestWithEmptyFields { + @BeforeEach + void mock() { + document = buildXMLDocument("<root />"); + } + + @DisplayName("should include empty header field") + @ParameterizedTest + @MethodSource("headerNames") + void shouldIncludeAllHeaderField(String headerName) { + var resultHeaderMap = adapter.createHeaderMap(document); + + assertThat(resultHeaderMap).containsEntry(headerName, ""); + } + + private static Stream<Arguments> headerNames() { + return HEADER_ATTRIBUTE_NAMES.stream().map(Arguments::of); + } + + @DisplayName("should not include custom header field") + @ParameterizedTest + @MethodSource("customHeaderNames") + void shouldNotIncludeAllCustomHeaderField(String headerName) { + var resultHeaderMap = adapter.createHeaderMap(document); + + assertThat(resultHeaderMap).doesNotContainKey(headerName); + } + + private static Stream<Arguments> customHeaderNames() { + return CUSTOM_HEADER_ATTRIBUTE_NAMES.stream().map(Arguments::of); + } + } + } + + @DisplayName("adapt by representation") + @Nested + class TestAdaptByRepresentation { + + @Mock + private FormData formData; + + @DisplayName("should throw exception without xml document") + @Test + void shouldThrowExceptionWithoutXmlDocument() { + doReturn(Optional.empty()) + .when(adapter).findIntelliFormXMLRepresentation(formData); + + assertThrows(TechnicalException.class, () -> + adapter.adaptByRepresentations(formData) + ); + } + + @DisplayName("with xml document") + @Nested + class TestWithXmlDocument { + + @Mock + private IncomingFileGroup attachmentGroup; + + @Mock + private IncomingFile xmlRepresentation; + + @Mock + private IncomingFile otherRepresentation; + + @Mock + private Document document; + + @Mock + private Map<String, Object> headerFields; + + private List<IncomingFileGroup> attachments; + private List<IncomingFile> representations; + + @BeforeEach + void mock() { + attachments = List.of(attachmentGroup); + representations = List.of(xmlRepresentation, otherRepresentation); + + when(formData.getRepresentations()).thenReturn(representations); + when(formData.getAttachments()).thenReturn(attachments); + doReturn(Optional.of(document)).when(adapter).findIntelliFormXMLRepresentation(formData); + + doReturn(Map.of(DOCUMENT_TEST_KEY, DOCUMENT_TEST_VALUE).entrySet().stream()) + .when(adapter).getFormDataEntriesFromDocument(document, attachments); + + doReturn(headerFields) + .when(adapter).createHeaderMap(document); + } + + @DisplayName("should have document field") + @Test + void shouldHaveDocumentField() { + var documentValue = obtainMappingByKey(DOCUMENT_TEST_KEY); + + assertThat(documentValue).isEqualTo(DOCUMENT_TEST_VALUE); + } + + @DisplayName("should have header field") + @Test + void shouldHaveHeaderField() { + var headerValue = obtainMappingByKey(HEADER_FIELD); + + assertThat(headerValue).isEqualTo(headerFields); + } + + private Object obtainMappingByKey(String key) { + var formDataResult = adapter.adaptByRepresentations(formData); + + return formDataResult.getFormData().get(key); + } + + @DisplayName("should have attachments") + @Test + void shouldHaveAttachments() { + var formDataResult = adapter.adaptByRepresentations(formData); + + assertThat(formDataResult.getAttachments()).isEqualTo(attachments); + } + + @DisplayName("should have representations") + @Test + void shouldHaveRepresentations() { + var formDataResult = adapter.adaptByRepresentations(formData); + + assertThat(formDataResult.getRepresentations()).isEqualTo(representations); + } + } + } + + private Document buildXMLDocument(String xmlString) { + try { + return DocumentBuilderFactory.newInstance() + .newDocumentBuilder() + .parse(new InputSource(new StringReader(xmlString))); + } catch (ParserConfigurationException | IOException | SAXException e) { + throw new RuntimeException(e); + } + } + +} diff --git a/intelliform-adapter/src/test/java/de/ozgcloud/eingang/intelliform/JsonServiceTest.java b/semantik-adapter/src/test/java/de/ozgcloud/eingang/semantik/enginebased/afm/intelliform/JsonServiceTest.java similarity index 94% rename from intelliform-adapter/src/test/java/de/ozgcloud/eingang/intelliform/JsonServiceTest.java rename to semantik-adapter/src/test/java/de/ozgcloud/eingang/semantik/enginebased/afm/intelliform/JsonServiceTest.java index e32bfa9c633fa6e36169d7b0674f59ab0c4ca59f..c9212b4dc604a48ae5a085da63b7ac3d62720087 100644 --- a/intelliform-adapter/src/test/java/de/ozgcloud/eingang/intelliform/JsonServiceTest.java +++ b/semantik-adapter/src/test/java/de/ozgcloud/eingang/semantik/enginebased/afm/intelliform/JsonServiceTest.java @@ -1,4 +1,4 @@ -package de.ozgcloud.eingang.intelliform; +package de.ozgcloud.eingang.semantik.enginebased.afm.intelliform; import static org.assertj.core.api.Assertions.*; import static org.mockito.ArgumentMatchers.*; @@ -21,6 +21,7 @@ import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.ObjectMapper; import de.ozgcloud.common.errorhandling.TechnicalException; +import de.ozgcloud.eingang.semantik.enginebased.afm.intelliform.JsonService; import lombok.SneakyThrows; class JsonServiceTest { diff --git a/intelliform-adapter/src/test/java/de/ozgcloud/eingang/intelliform/XmlToJavaMapsMapperTest.java b/semantik-adapter/src/test/java/de/ozgcloud/eingang/semantik/enginebased/afm/intelliform/XmlToJavaMapsMapperTest.java similarity index 99% rename from intelliform-adapter/src/test/java/de/ozgcloud/eingang/intelliform/XmlToJavaMapsMapperTest.java rename to semantik-adapter/src/test/java/de/ozgcloud/eingang/semantik/enginebased/afm/intelliform/XmlToJavaMapsMapperTest.java index ea6f5149f2aaba2246891aaefede93950f120a7d..37df5097b555ee8308b53570108c02024fc2745f 100644 --- a/intelliform-adapter/src/test/java/de/ozgcloud/eingang/intelliform/XmlToJavaMapsMapperTest.java +++ b/semantik-adapter/src/test/java/de/ozgcloud/eingang/semantik/enginebased/afm/intelliform/XmlToJavaMapsMapperTest.java @@ -21,7 +21,7 @@ * Die sprachspezifischen Genehmigungen und Beschränkungen * unter der Lizenz sind dem Lizenztext zu entnehmen. */ -package de.ozgcloud.eingang.intelliform; +package de.ozgcloud.eingang.semantik.enginebased.afm.intelliform; import static org.assertj.core.api.Assertions.*; import static org.mockito.ArgumentMatchers.*; @@ -31,8 +31,6 @@ import java.util.Collections; import java.util.List; import java.util.Map; -import jakarta.xml.soap.Node; - import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Nested; @@ -40,6 +38,7 @@ import org.junit.jupiter.api.Test; import org.mockito.InjectMocks; import org.mockito.Mock; import org.w3c.dom.Document; +import org.w3c.dom.Node; import de.ozgcloud.common.errorhandling.TechnicalException; @@ -327,4 +326,4 @@ class XmlToJavaMapsMapperTest { private Map<String, Object> mapXmlToJavaMaps() { return mapper.mapXmlToJavaMaps(document); } -} \ No newline at end of file +} diff --git a/semantik-adapter/src/test/java/de/ozgcloud/eingang/semantik/formbased/DFoerdermittelFormBasedMapperTest.java b/semantik-adapter/src/test/java/de/ozgcloud/eingang/semantik/enginebased/dfoerdermittel/DFoerdermittelEngineBasedSemantikAdapterTest.java similarity index 58% rename from semantik-adapter/src/test/java/de/ozgcloud/eingang/semantik/formbased/DFoerdermittelFormBasedMapperTest.java rename to semantik-adapter/src/test/java/de/ozgcloud/eingang/semantik/enginebased/dfoerdermittel/DFoerdermittelEngineBasedSemantikAdapterTest.java index dc9d2d172dde4c1e84debbc0bb270e3e3437e8cb..cccd254d34afde615debd689c4c5f73fd1c7dd5d 100644 --- a/semantik-adapter/src/test/java/de/ozgcloud/eingang/semantik/formbased/DFoerdermittelFormBasedMapperTest.java +++ b/semantik-adapter/src/test/java/de/ozgcloud/eingang/semantik/enginebased/dfoerdermittel/DFoerdermittelEngineBasedSemantikAdapterTest.java @@ -1,4 +1,4 @@ -package de.ozgcloud.eingang.semantik.formbased; +package de.ozgcloud.eingang.semantik.enginebased.dfoerdermittel; import static org.assertj.core.api.Assertions.*; import static org.assertj.core.api.InstanceOfAssertFactories.*; @@ -11,8 +11,6 @@ import java.util.Map; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; -import org.mockito.ArgumentCaptor; -import org.mockito.Captor; import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.Spy; @@ -28,11 +26,11 @@ import de.ozgcloud.eingang.common.formdata.StringBasedIdentifier; import de.ozgcloud.eingang.common.formdata.ZustaendigeStelle; import de.ozgcloud.eingang.semantik.enginebased.ServiceKontoBuildHelper; -class DFoerdermittelFormBasedMapperTest { +class DFoerdermittelEngineBasedSemantikAdapterTest { @Spy @InjectMocks - private DFoerdermittelFormBasedMapper mapper; + private DFoerdermittelEngineBasedSemantikAdapter adapter; @Mock private ServiceKontoBuildHelper serviceKontoHelper; @@ -42,14 +40,14 @@ class DFoerdermittelFormBasedMapperTest { @Test void shouldBeTrueWithFachnachricht() { - var responsible = mapper.isResponsible(createWithFachnachricht()); + var responsible = adapter.isResponsible(createWithFachnachricht()); assertThat(responsible).isTrue(); } @Test void shouldBeFalseForOuther() { - var responsible = mapper.isResponsible(FormDataTestFactory.create()); + var responsible = adapter.isResponsible(FormDataTestFactory.create()); assertThat(responsible).isFalse(); } @@ -62,21 +60,21 @@ class DFoerdermittelFormBasedMapperTest { class ExtractData { @Test void shouldHaveFormData() { - var result = mapper.extractFormDataFormXML(TestUtils.loadFile("xta/Beispieldatensatz_Fachnachricht.xml")); + var result = adapter.extractFormDataFormXML(TestUtils.loadFile("xta/Beispieldatensatz_Fachnachricht.xml")); assertThat(result).isNotNull(); } @Test void shouldHavePages() { - var result = mapper.extractFormDataFormXML(TestUtils.loadFile("xta/Beispieldatensatz_Fachnachricht.xml")); + var result = adapter.extractFormDataFormXML(TestUtils.loadFile("xta/Beispieldatensatz_Fachnachricht.xml")); assertThat(result).containsKey("Pages"); } @Test void shouldHaveInboxRef() { - var result = mapper.extractFormDataFormXML(TestUtils.loadFile("xta/Beispieldatensatz_Fachnachricht.xml")); + var result = adapter.extractFormDataFormXML(TestUtils.loadFile("xta/Beispieldatensatz_Fachnachricht.xml")); assertThat(result).containsEntry("InboxReference", "sh/sh/4dd01647-b9d9-4775-1b50-08da3d83800a"); } @@ -89,27 +87,27 @@ class DFoerdermittelFormBasedMapperTest { @Test void shouldCallExtractData() { - doReturn(extracted).when(mapper).extractFormDataFormXML(any()); + doReturn(extracted).when(adapter).extractFormDataFormXML(any()); - mapper.parseFachnachricht(createWithFachnachricht(), createFachnachrichtFile()); + adapter.parseFachnachricht(createWithFachnachricht(), createFachnachrichtFile()); - verify(mapper).extractFormDataFormXML(notNull()); + verify(adapter).extractFormDataFormXML(notNull()); } @Test void shouldAddMap() { - doReturn(extracted).when(mapper).extractFormDataFormXML(any()); + doReturn(extracted).when(adapter).extractFormDataFormXML(any()); - var result = mapper.parseFachnachricht(createWithFachnachricht(), createFachnachrichtFile()); + var result = adapter.parseFachnachricht(createWithFachnachricht(), createFachnachrichtFile()); assertThat(result.getFormData()).containsEntry("Fachnachricht", extracted); } @Test void shouldIgnoreEmptyData() { - doReturn(Collections.emptyMap()).when(mapper).extractFormDataFormXML(any()); + doReturn(Collections.emptyMap()).when(adapter).extractFormDataFormXML(any()); - var result = mapper.parseFachnachricht(createWithFachnachricht(), createFachnachrichtFile()); + var result = adapter.parseFachnachricht(createWithFachnachricht(), createFachnachrichtFile()); assertThat(result.getFormData()).doesNotContainKey("Fachnachricht"); } @@ -137,27 +135,37 @@ class DFoerdermittelFormBasedMapperTest { @Nested class TestProcessFachnachricht { - @Captor - private ArgumentCaptor<Map<String, Object>> fachnachrichtCaptor; + @Mock + FormData formData0; - @Test - void shouldCallAddServiceKonto() { - var formData = DFoerdermittelFormDataTestFactory.create(); + @Mock + FormData formData1; + + @Mock + FormData formData2; - mapper.processFachnachricht(formData); + @Mock + FormData formData3; - verify(mapper).addServiceKonto(same(formData), fachnachrichtCaptor.capture()); - assertThat(fachnachrichtCaptor.getValue()).containsAllEntriesOf(DFoerdermittelFormDataTestFactory.createFachnachrichtMap()); + @Mock + FormData formData4; + + @BeforeEach + void mock() { + var formData = DFoerdermittelFormDataTestFactory.create(); + var fachnachrichtMap = DFoerdermittelFormDataTestFactory.createFachnachrichtMap(); + when(formData0.getFormData()).thenReturn(formData.getFormData()); + doReturn(formData1).when(adapter).addFormName(formData0); + doReturn(formData2).when(adapter).addFormEngineName(formData1); + doReturn(formData3).when(adapter).addServiceKonto(formData2, fachnachrichtMap); + doReturn(formData4).when(adapter).addOrganisationsEinheitId(formData3, fachnachrichtMap); } @Test - void shouldCallAddOrganisationsEinheitId() { - var extened = DFoerdermittelFormDataTestFactory.create(); - doReturn(extened).when(mapper).addServiceKonto(any(), any()); + void shouldReturn() { + var processedFormData = adapter.processFachnachricht(formData0); - mapper.processFachnachricht(DFoerdermittelFormDataTestFactory.create()); - - verify(mapper).addOrganisationsEinheitId(same(extened), notNull()); + assertThat(processedFormData).isEqualTo(formData4); } } @@ -171,7 +179,7 @@ class DFoerdermittelFormBasedMapperTest { @Test void shouldHaveServiceKonto() { - var formData = mapper.addServiceKonto(DFoerdermittelFormDataTestFactory.create(), + var formData = adapter.addServiceKonto(DFoerdermittelFormDataTestFactory.create(), DFoerdermittelFormDataTestFactory.createFachnachrichtMap()); assertThat(formData.getHeader().getServiceKonto().getPostfachAddresses().get(0).getIdentifier()) @@ -181,7 +189,7 @@ class DFoerdermittelFormBasedMapperTest { @Test void shouldRemovePrefix() { - mapper.addServiceKonto(DFoerdermittelFormDataTestFactory.create(), DFoerdermittelFormDataTestFactory.createFachnachrichtMap()); + adapter.addServiceKonto(DFoerdermittelFormDataTestFactory.create(), DFoerdermittelFormDataTestFactory.createFachnachrichtMap()); verify(serviceKontoHelper).buildOsiServiceKonto(DFoerdermittelFormDataTestFactory.POSTFACH_ID); } @@ -191,14 +199,14 @@ class DFoerdermittelFormBasedMapperTest { class TestExtractPrefix { @Test void shouldRemoveAllBeforeLastSlash() { - var result = mapper.extractPrefix("bla/bla/bla/12345"); + var result = adapter.extractPrefix("bla/bla/bla/12345"); assertThat(result).isEqualTo("12345"); } @Test void shouldBeFineWithoutSlash() { - var result = mapper.extractPrefix("12345"); + var result = adapter.extractPrefix("12345"); assertThat(result).isEqualTo("12345"); } @@ -208,11 +216,35 @@ class DFoerdermittelFormBasedMapperTest { class TestAddOrganisationsEinheitId { @Test void shouldHaveOrganisationsEinheitId() { - var formData = mapper.addOrganisationsEinheitId(DFoerdermittelFormDataTestFactory.create(), + var formData = adapter.addOrganisationsEinheitId(DFoerdermittelFormDataTestFactory.create(), DFoerdermittelFormDataTestFactory.createFachnachrichtMap()); assertThat(formData.getZustaendigeStelle()).isNotNull().extracting(ZustaendigeStelle::getOrganisationseinheitenId) .isEqualTo(DFoerdermittelFormDataTestFactory.ORGANISATIONS_EINHEIT_ID); } } + + @Nested + class TestAddFormName { + + @Test + void shouldHaveFormName() { + var formData = adapter.addFormName(DFoerdermittelFormDataTestFactory.create()); + + assertThat(formData.getHeader().getFormName()).isEqualTo("dFördermittelantrag"); + } + + } + + @Nested + class TestAddFormEngineName { + + @Test + void shouldHaveFormEngineName() { + var formData = adapter.addFormEngineName(DFoerdermittelFormDataTestFactory.create()); + + assertThat(formData.getHeader().getFormEngineName()).isEqualTo("dFördermittelantrag"); + } + + } } diff --git a/semantik-adapter/src/test/java/de/ozgcloud/eingang/semantik/formbased/DFoerdermittelFormDataTestFactory.java b/semantik-adapter/src/test/java/de/ozgcloud/eingang/semantik/enginebased/dfoerdermittel/DFoerdermittelFormDataTestFactory.java similarity index 90% rename from semantik-adapter/src/test/java/de/ozgcloud/eingang/semantik/formbased/DFoerdermittelFormDataTestFactory.java rename to semantik-adapter/src/test/java/de/ozgcloud/eingang/semantik/enginebased/dfoerdermittel/DFoerdermittelFormDataTestFactory.java index fd333fc59cea56b4bfba0b21994f5169f305a5a4..b99c66e48559d39b5c58e747c145a58dc0490363 100644 --- a/semantik-adapter/src/test/java/de/ozgcloud/eingang/semantik/formbased/DFoerdermittelFormDataTestFactory.java +++ b/semantik-adapter/src/test/java/de/ozgcloud/eingang/semantik/enginebased/dfoerdermittel/DFoerdermittelFormDataTestFactory.java @@ -1,4 +1,4 @@ -package de.ozgcloud.eingang.semantik.formbased; +package de.ozgcloud.eingang.semantik.enginebased.dfoerdermittel; import java.util.Map; 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 cc186d6b99d8f020ff07374682eb34f7b751b407..47c563508627226dac6341fe8d6e4b36f9062b70 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 @@ -58,9 +58,7 @@ import lombok.SneakyThrows; public class FormSolutionsEngineBasedAdapterITCase { private static final String ZIP_CONTENT_TYPE = "application/zip"; - private static final String FILE_NAME_ZIP_ATTACHMENT = "attachment-2files.zip"; - public static final String FILE_NAME_PDF_REP = "eingang.pdf"; - public static final String FILE_NAME_JSON_REP = "form-data.json"; + private static final String FILE_NAME_ZIP_ATTACHMENT = "formsolutions/attachment-2files.zip"; @MockBean private SemantikAdapter semantikAdapter; diff --git a/semantik-adapter/src/test/java/de/ozgcloud/eingang/semantik/enginebased/xta/XtaZipRepresentationsMapperTest.java b/semantik-adapter/src/test/java/de/ozgcloud/eingang/semantik/enginebased/xta/XtaZipRepresentationsMapperTest.java deleted file mode 100644 index 56b515e083af42c3b22fc050990df4765832a277..0000000000000000000000000000000000000000 --- a/semantik-adapter/src/test/java/de/ozgcloud/eingang/semantik/enginebased/xta/XtaZipRepresentationsMapperTest.java +++ /dev/null @@ -1,122 +0,0 @@ -package de.ozgcloud.eingang.semantik.enginebased.xta; - -import static org.assertj.core.api.Assertions.*; -import static org.mockito.ArgumentMatchers.*; -import static org.mockito.Mockito.*; - -import java.io.InputStream; -import java.util.List; -import java.util.stream.IntStream; - -import org.junit.jupiter.api.Nested; -import org.junit.jupiter.api.Test; -import org.mockito.MockedStatic; -import org.mockito.Mockito; -import org.mockito.Spy; - -import de.ozgcloud.eingang.common.formdata.FormData; -import de.ozgcloud.eingang.common.formdata.IncomingFile; -import de.ozgcloud.eingang.common.formdata.IncomingFileTestFactory; -import de.ozgcloud.eingang.semantik.common.ZipAttachmentReader; -import lombok.SneakyThrows; - -class XtaZipRepresentationsMapperTest { - - private static final String ZIP_CONTENT_TYPE = "application/zip"; - - @Spy - private final XtaZipRepresentationsMapper mapper = new XtaZipRepresentationsMapper(); - - @Nested - class TestExtractZipFileEctract { - - @Test - void shouldExtractZipFiles() { - try (var zipAttachment = Mockito.mockStatic(ZipAttachmentReader.class)) { - initZipRepresentationMocks(zipAttachment); - - var formData = mapper.parseFormData(createTestFormDataWithZipRepresentation()); - - assertThat(formData.getRepresentations()).hasSize(3); - } - } - - FormData createTestFormDataWithZipRepresentation() { - List<IncomingFile> representations = List.of( - IncomingFileTestFactory.createBuilder() - .name("attachments.zip") - .contentType(ZIP_CONTENT_TYPE) - .build()); - - return FormData.builder().representations(representations).numberOfRepresentations(representations.size()).build(); - } - - @Test - void shouldSetRepresentationsNumber() { - try (var zipAttachment = Mockito.mockStatic(ZipAttachmentReader.class)) { - initZipRepresentationMocks(zipAttachment); - - var formData = mapper.parseFormData(createTestFormDataWithZipRepresentation()); - - assertThat(formData.getNumberOfRepresentations()).isEqualTo(3); - } - } - - @Test - void shouldIgnoreNonZipFiles() { - try (var zipAttachment = Mockito.mockStatic(ZipAttachmentReader.class)) { - - var formData = mapper.parseFormData(createTestFormDataWithoutZipRepresentation()); - - assertThat(formData.getNumberOfRepresentations()).isEqualTo(1); - } - } - - FormData createTestFormDataWithoutZipRepresentation() { - List<IncomingFile> representations = List.of( - IncomingFileTestFactory.create()); - return FormData.builder().representations(representations).numberOfRepresentations(representations.size()).build(); - } - - @Test - void shouldNotDeleteOriginalZipFile() { - try (var zipAttachment = Mockito.mockStatic(ZipAttachmentReader.class)) { - initZipRepresentationMocks(zipAttachment); - - var formData = mapper.parseFormData(createTestFormDataWithZipRepresentation()); - - assertThat(formData.getRepresentations()).map(IncomingFile::getContentType) - .filteredOn(e -> e.equals(XtaZipRepresentationsMapper.ZIP_CONTENT_TYPE)).hasSize(1); - } - } - - @Test - void shouldDoNothingOnEmptyRepresentations() { - try (var zipAttachment = Mockito.mockStatic(ZipAttachmentReader.class)) { - - var formData = mapper.parseFormData(createTestFormDataWithoutRepresentation()); - - assertThat(formData.getRepresentations()).isEmpty(); - } - } - - FormData createTestFormDataWithoutRepresentation() { - return FormData.builder().numberOfRepresentations(0).build(); - } - } - - @Test - void testIsZipFilePredicate() { - - assertThat(XtaZipRepresentationsMapper.IS_ZIP_FILE.test(IncomingFileTestFactory.create())).isFalse(); - assertThat(XtaZipRepresentationsMapper.IS_ZIP_FILE.test(IncomingFileTestFactory.createBuilder().contentType(ZIP_CONTENT_TYPE).build())) - .isTrue(); - } - - @SneakyThrows - private static void initZipRepresentationMocks(MockedStatic<ZipAttachmentReader> zipAttachmentMock) { - var contentEntries = IntStream.range(0, 2).boxed().map(i -> IncomingFileTestFactory.createBuilder().name(i.toString()).build()).toList(); - ZipAttachmentReader mock = when(mock(ZipAttachmentReader.class).readContent()).thenReturn(contentEntries).getMock(); - zipAttachmentMock.when(() -> ZipAttachmentReader.from(any(InputStream.class), any())).thenReturn(mock); - } -} diff --git a/semantik-adapter/src/test/resources/formsolutions/attachment-2files.zip b/semantik-adapter/src/test/resources/formsolutions/attachment-2files.zip new file mode 100644 index 0000000000000000000000000000000000000000..1cd6370639e85040002e6b17df7dc2c36b877673 Binary files /dev/null and b/semantik-adapter/src/test/resources/formsolutions/attachment-2files.zip differ diff --git a/intelliform-adapter/src/test/resources/intelliform/EinfachesFormularZweiAnhaengeXmlDaten1.xml b/semantik-adapter/src/test/resources/intelliform/EinfachesFormularZweiAnhaengeXmlDaten1.xml similarity index 100% rename from intelliform-adapter/src/test/resources/intelliform/EinfachesFormularZweiAnhaengeXmlDaten1.xml rename to semantik-adapter/src/test/resources/intelliform/EinfachesFormularZweiAnhaengeXmlDaten1.xml diff --git a/intelliform-adapter/src/test/resources/intelliform/EinfachesFormularZweiAnhaengeXmlDatenVerschachtelt.xml b/semantik-adapter/src/test/resources/intelliform/EinfachesFormularZweiAnhaengeXmlDatenVerschachtelt.xml similarity index 100% rename from intelliform-adapter/src/test/resources/intelliform/EinfachesFormularZweiAnhaengeXmlDatenVerschachtelt.xml rename to semantik-adapter/src/test/resources/intelliform/EinfachesFormularZweiAnhaengeXmlDatenVerschachtelt.xml diff --git a/intelliform-adapter/src/test/resources/intelliform/FormularSoapRequest_WithContent_XML-Daten-1.xml b/semantik-adapter/src/test/resources/intelliform/FormularSoapRequest_WithContent_XML-Daten-1.xml similarity index 100% rename from intelliform-adapter/src/test/resources/intelliform/FormularSoapRequest_WithContent_XML-Daten-1.xml rename to semantik-adapter/src/test/resources/intelliform/FormularSoapRequest_WithContent_XML-Daten-1.xml diff --git a/intelliform-adapter/src/test/resources/intelliform/SimpleFormDataMapperTestFile.xml b/semantik-adapter/src/test/resources/intelliform/SimpleFormDataMapperTestFile.xml similarity index 100% rename from intelliform-adapter/src/test/resources/intelliform/SimpleFormDataMapperTestFile.xml rename to semantik-adapter/src/test/resources/intelliform/SimpleFormDataMapperTestFile.xml diff --git a/intelliform-adapter/src/test/resources/intelliform/XML-Daten-1-SoapRequest.xml b/semantik-adapter/src/test/resources/intelliform/XML-Daten-1-SoapRequest.xml similarity index 100% rename from intelliform-adapter/src/test/resources/intelliform/XML-Daten-1-SoapRequest.xml rename to semantik-adapter/src/test/resources/intelliform/XML-Daten-1-SoapRequest.xml diff --git a/intelliform-adapter/src/test/resources/intelliform/XML-Daten_Gewerbe.xml b/semantik-adapter/src/test/resources/intelliform/XML-Daten_Gewerbe.xml similarity index 100% rename from intelliform-adapter/src/test/resources/intelliform/XML-Daten_Gewerbe.xml rename to semantik-adapter/src/test/resources/intelliform/XML-Daten_Gewerbe.xml diff --git a/intelliform-adapter/src/test/resources/intelliform/XML-Daten_Gewerbe_organisationseinheitenID.xml b/semantik-adapter/src/test/resources/intelliform/XML-Daten_Gewerbe_organisationseinheitenID.xml similarity index 100% rename from intelliform-adapter/src/test/resources/intelliform/XML-Daten_Gewerbe_organisationseinheitenID.xml rename to semantik-adapter/src/test/resources/intelliform/XML-Daten_Gewerbe_organisationseinheitenID.xml diff --git a/intelliform-adapter/src/test/resources/intelliform/XML-Daten_Gewerbe_organisationseinheitenID_und_zustaendigstelle.xml b/semantik-adapter/src/test/resources/intelliform/XML-Daten_Gewerbe_organisationseinheitenID_und_zustaendigstelle.xml similarity index 100% rename from intelliform-adapter/src/test/resources/intelliform/XML-Daten_Gewerbe_organisationseinheitenID_und_zustaendigstelle.xml rename to semantik-adapter/src/test/resources/intelliform/XML-Daten_Gewerbe_organisationseinheitenID_und_zustaendigstelle.xml diff --git a/intelliform-adapter/src/test/resources/intelliform/XML-Daten_Strassengefaelle.xml b/semantik-adapter/src/test/resources/intelliform/XML-Daten_Strassengefaelle.xml similarity index 100% rename from intelliform-adapter/src/test/resources/intelliform/XML-Daten_Strassengefaelle.xml rename to semantik-adapter/src/test/resources/intelliform/XML-Daten_Strassengefaelle.xml diff --git a/intelliform-adapter/src/test/resources/intelliform/XML-Keine_Daten.xml b/semantik-adapter/src/test/resources/intelliform/XML-Keine_Daten.xml similarity index 100% rename from intelliform-adapter/src/test/resources/intelliform/XML-Keine_Daten.xml rename to semantik-adapter/src/test/resources/intelliform/XML-Keine_Daten.xml diff --git a/intelliform-adapter/src/test/resources/intelliform/andererName-Daten.xml b/semantik-adapter/src/test/resources/intelliform/andererName-Daten.xml similarity index 100% rename from intelliform-adapter/src/test/resources/intelliform/andererName-Daten.xml rename to semantik-adapter/src/test/resources/intelliform/andererName-Daten.xml diff --git a/xta-adapter/pom.xml b/xta-adapter/pom.xml index 99d04ee83d680b95aed8a21d06f39cd5bcdb179c..6557a321b925d9653ec245854de08eb44d3c9b91 100644 --- a/xta-adapter/pom.xml +++ b/xta-adapter/pom.xml @@ -83,6 +83,7 @@ <artifactId>spring-boot-configuration-processor</artifactId> <optional>true</optional> </dependency> + <!-- Test --> <dependency> <groupId>com.squareup.okio</groupId> <artifactId>okio</artifactId> @@ -95,6 +96,12 @@ <version>${mockwebserver.version}</version> <scope>test</scope> </dependency> + <dependency> + <groupId>de.ozgcloud.eingang</groupId> + <artifactId>common</artifactId> + <type>test-jar</type> + <scope>test</scope> + </dependency> </dependencies> <build> diff --git a/xta-adapter/src/main/java/de/ozgcloud/eingang/xdomea/XdomeaMessageData.java b/xta-adapter/src/main/java/de/ozgcloud/eingang/xdomea/XdomeaMessageData.java new file mode 100644 index 0000000000000000000000000000000000000000..432b06c5273798eb5bf67ff0666dea40211c69ad --- /dev/null +++ b/xta-adapter/src/main/java/de/ozgcloud/eingang/xdomea/XdomeaMessageData.java @@ -0,0 +1,17 @@ +package de.ozgcloud.eingang.xdomea; + +import java.util.List; + +import de.ozgcloud.eingang.common.formdata.IncomingFile; +import de.ozgcloud.eingang.common.formdata.IncomingFileGroup; +import lombok.Builder; +import lombok.Singular; + +@Builder +public record XdomeaMessageData( + IncomingFile metadataFile, + List<IncomingFile> representations, + @Singular + List<IncomingFileGroup> attachments +) { +} diff --git a/xta-adapter/src/main/java/de/ozgcloud/eingang/xdomea/XdomeaMessageDataMapper.java b/xta-adapter/src/main/java/de/ozgcloud/eingang/xdomea/XdomeaMessageDataMapper.java new file mode 100644 index 0000000000000000000000000000000000000000..e6d9f6836b5ef0d26087356de2545d512683b863 --- /dev/null +++ b/xta-adapter/src/main/java/de/ozgcloud/eingang/xdomea/XdomeaMessageDataMapper.java @@ -0,0 +1,111 @@ +package de.ozgcloud.eingang.xdomea; + +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import org.springframework.stereotype.Component; + +import de.ozgcloud.eingang.common.errorhandling.TechnicalException; +import de.ozgcloud.eingang.common.formdata.IncomingFile; +import de.ozgcloud.eingang.common.formdata.IncomingFileGroup; +import lombok.RequiredArgsConstructor; +import lombok.extern.log4j.Log4j2; + +@Component +@Log4j2 +@RequiredArgsConstructor +public class XdomeaMessageDataMapper { + static final String XDOMEA_0201_XML_FILE_NAME_SUFFIX = "_Geschaeftsgang.Geschaeftsgang.0201.xml"; + static final String ATTACHMENT_GROUP_NAME = "Dokument"; + + private final XdomeaXMLValueReader valueReader; + + public XdomeaMessageData mapIncomingFilesToXdomeaMessageData(List<IncomingFile> incomingFileList) { + var xdomeaXMLFile = findXdomeaXMLFile(incomingFileList); + var representationFileNames = valueReader.readRepresentationFileNames(xdomeaXMLFile); + var attachmentFileNames = getFileNamesExcluding( + incomingFileList, + Stream.concat(Stream.of(xdomeaXMLFile.getName()), representationFileNames.stream()) + ); + + var fileNameToFileMap = createFileNameToIncomingFileMap(incomingFileList); + return XdomeaMessageData.builder() + .metadataFile(xdomeaXMLFile) + .representations(getRepresentations(representationFileNames, fileNameToFileMap)) + .attachments(getAttachments(attachmentFileNames, fileNameToFileMap)) + .build(); + } + + private Map<String, IncomingFile> createFileNameToIncomingFileMap(List<IncomingFile> incomingFileList) { + return incomingFileList.stream() + .collect(Collectors.toMap(IncomingFile::getName, file -> file)); + } + + private Stream<String> getFileNamesExcluding(List<IncomingFile> incomingFileList, Stream<String> excludedFileNames) { + return dropNames( + incomingFileList.stream().map(IncomingFile::getName), + excludedFileNames.collect(Collectors.toSet()) + ); + } + + private List<IncomingFile> getRepresentations(List<String> representationFileNames, Map<String, IncomingFile> fileNameToFileMap) { + return getFilesByName( + movePrimaryRepresentationFileNameToFirstPosition(representationFileNames), + fileNameToFileMap + ); + } + + private List<IncomingFileGroup> getAttachments(Stream<String> attachmentFileNames, Map<String, IncomingFile> fileNameToFileMap) { + return Stream.of(IncomingFileGroup.builder() + .name(ATTACHMENT_GROUP_NAME) + .files( + getFilesByName( + attachmentFileNames, + fileNameToFileMap + ) + ) + .build()) + // Do not include empty attachment group + .filter(group -> !group.getFiles().isEmpty()) + .toList(); + } + + private Stream<String> movePrimaryRepresentationFileNameToFirstPosition(List<String> representationFileNames) { + var primaryRepresentationFileName = findPrimaryRepresentationName(representationFileNames); + return Stream.concat( + Stream.of(primaryRepresentationFileName), + dropNames(representationFileNames.stream(), Set.of(primaryRepresentationFileName)) + ); + } + + private List<IncomingFile> getFilesByName(Stream<String> names, Map<String, IncomingFile> fileNameToFileMap) { + return names.map(fileNameToFileMap::get).toList(); + } + + private Stream<String> dropNames(Stream<String> names, Set<String> namesToDrop) { + return names.filter(name -> !namesToDrop.contains(name)); + } + + String findPrimaryRepresentationName(List<String> representationFileNames) { + var xmlFileNames = representationFileNames.stream() + .filter(name -> name.endsWith(".xml")) + .toList(); + if (xmlFileNames.isEmpty()) { + throw new TechnicalException("No xml representation file name found!"); + } else if (xmlFileNames.size() > 1) { + LOG.warn("There is more than one xml representations. Choosing the first of {}.", xmlFileNames.size()); + } + return xmlFileNames.getFirst(); + } + + IncomingFile findXdomeaXMLFile(List<IncomingFile> incomingFileList) { + return incomingFileList.stream() + .filter(file -> file.getName().endsWith(XDOMEA_0201_XML_FILE_NAME_SUFFIX)) + .findFirst() + .orElseThrow(() -> new TechnicalException("Primary xdomea xml representation not found!")); + } + +} diff --git a/xta-adapter/src/main/java/de/ozgcloud/eingang/xdomea/XdomeaXMLValueReader.java b/xta-adapter/src/main/java/de/ozgcloud/eingang/xdomea/XdomeaXMLValueReader.java new file mode 100644 index 0000000000000000000000000000000000000000..f0fc982a33fc939726023ff751d36873e811b105 --- /dev/null +++ b/xta-adapter/src/main/java/de/ozgcloud/eingang/xdomea/XdomeaXMLValueReader.java @@ -0,0 +1,60 @@ +package de.ozgcloud.eingang.xdomea; + +import static de.ozgcloud.eingang.common.xml.XMLHelper.*; + +import java.util.List; +import java.util.stream.IntStream; +import java.util.stream.Stream; + +import javax.xml.xpath.XPathConstants; +import javax.xml.xpath.XPathExpression; +import javax.xml.xpath.XPathExpressionException; + +import org.springframework.stereotype.Component; +import org.w3c.dom.Element; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; + +import de.ozgcloud.eingang.common.errorhandling.TechnicalException; +import de.ozgcloud.eingang.common.formdata.IncomingFile; +import de.ozgcloud.eingang.common.xml.XMLHelper; + +@Component +public class XdomeaXMLValueReader { + + private static final String DATEINAME_NODE_QUERY_STRING = "//Hauptobjekt//Dateiname"; + private static final XPathExpression DATEINAME_NODE_QUERY = compileXPathExpression(DATEINAME_NODE_QUERY_STRING); + + public List<String> readRepresentationFileNames(IncomingFile xdomeaXMLFile) { + return getTextsFromNodes( + queryDateinameNodeList( + XMLHelper.parseDocument(xdomeaXMLFile) + .getDocumentElement() + ) + ); + } + + private NodeList queryDateinameNodeList(Element contextElement) { + try { + return (NodeList) DATEINAME_NODE_QUERY + .evaluate( + contextElement, + XPathConstants.NODESET + ); + } catch (XPathExpressionException e) { + throw new TechnicalException("Failed to execute xpath search!", e); + } + } + + private List<String> getTextsFromNodes(NodeList nodeList) { + return streamNodeList(nodeList) + .map(Node::getTextContent) + .toList(); + } + + private Stream<Node> streamNodeList(NodeList nodeList) { + return IntStream.range(0, nodeList.getLength()) + .mapToObj(nodeList::item); + } + +} diff --git a/xta-adapter/src/main/java/de/ozgcloud/eingang/xta/XtaApplicationConfiguration.java b/xta-adapter/src/main/java/de/ozgcloud/eingang/xta/XtaApplicationConfiguration.java deleted file mode 100644 index 2b85133aa7ae8573b513cf189c4adeb3e12f96bf..0000000000000000000000000000000000000000 --- a/xta-adapter/src/main/java/de/ozgcloud/eingang/xta/XtaApplicationConfiguration.java +++ /dev/null @@ -1,15 +0,0 @@ -package de.ozgcloud.eingang.xta; - -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; - -import de.ozgcloud.eingang.semantik.enginebased.xta.XtaEngineBasedAdapter; - -@Configuration -class XtaApplicationConfiguration { - - @Bean - XtaEngineBasedAdapter engineBasedAdapter() { - return new XtaEngineBasedAdapter(); - } -} 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 new file mode 100644 index 0000000000000000000000000000000000000000..f2a5d411e664c3a06141e06b7798f07f8bb603ae --- /dev/null +++ b/xta-adapter/src/main/java/de/ozgcloud/eingang/xta/XtaIncomingFilesMapper.java @@ -0,0 +1,79 @@ +/* + * Copyright (C) 2024 Das Land Schleswig-Holstein vertreten durch das + * Ministerium für Energiewende, Klimaschutz, Umwelt und Natur + * Zentrales IT-Management + * + * Lizenziert unter der EUPL, Version 1.2 oder - sobald + * diese von der Europäischen Kommission genehmigt wurden - + * Folgeversionen der EUPL ("Lizenz"); + * Sie dürfen dieses Werk ausschließlich gemäß + * dieser Lizenz nutzen. + * Eine Kopie der Lizenz finden Sie hier: + * + * https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 + * + * Sofern nicht durch anwendbare Rechtsvorschriften + * gefordert oder in schriftlicher Form vereinbart, wird + * die unter der Lizenz verbreitete Software "so wie sie + * ist", OHNE JEGLICHE GEWÄHRLEISTUNG ODER BEDINGUNGEN - + * ausdrücklich oder stillschweigend - verbreitet. + * Die sprachspezifischen Genehmigungen und Beschränkungen + * unter der Lizenz sind dem Lizenztext zu entnehmen. + */ + +package de.ozgcloud.eingang.xta; + +import de.ozgcloud.eingang.common.formdata.IncomingFile; +import de.ozgcloud.eingang.common.zip.ZipAttachmentReader; +import lombok.extern.log4j.Log4j2; +import org.springframework.stereotype.Component; + +import java.util.Collection; +import java.util.List; +import java.util.Objects; +import java.util.function.Predicate; +import java.util.stream.Stream; + +@Log4j2 +@Component +public class XtaIncomingFilesMapper { + public static final String ZIP_CONTENT_TYPE = "application/zip"; + static final Predicate<IncomingFile> IS_ZIP_FILE = contentType -> ZIP_CONTENT_TYPE.equals(contentType.getContentType()); + + List<IncomingFile> toIncomingFiles(Collection<XtaFile> messageFiles) { + if (Objects.nonNull(messageFiles)) { + return messageFiles.stream() + .map(this::toIncomingFile) + .flatMap(this::extractZip) + .toList(); + } + return List.of(); + } + + IncomingFile toIncomingFile(XtaFile messageFile) { + if (!messageFile.contentType().equals(ZIP_CONTENT_TYPE)) { + LOG.warn("Expected XTA messageFile to be of content type " + ZIP_CONTENT_TYPE + ". Instead was " + messageFile.contentType()); + } + return IncomingFile.builder() + .name(messageFile.name()) + .contentType(messageFile.contentType()) + .file(messageFile.file()) + .size(messageFile.file().length()) + .build(); + } + + Stream<IncomingFile> extractZip(IncomingFile incomingFile) { + if (IS_ZIP_FILE.test(incomingFile)) { + try { + List<IncomingFile> extractedZips = ZipAttachmentReader.from(incomingFile.getContentStream(), incomingFile.getName()).readContent(); + return extractedZips.stream(); + } catch (RuntimeException e) { + LOG.error("Cannot read source ZIP. Not extracting file", e); + return Stream.of(incomingFile); + } + } + else { + return Stream.of(incomingFile); + } + } +} 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 f2e05fc7684fe33d1db3dd42ae46f1f044f23ef8..af561ff948a92bee781a4745cd9b98af4ece0c8e 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,50 +1,51 @@ package de.ozgcloud.eingang.xta; -import java.util.Objects; +import java.util.List; +import java.util.stream.Stream; +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.IncomingFile; +import de.ozgcloud.eingang.common.vorgang.VorgangNummerSupplier; +import de.ozgcloud.eingang.semantik.enginebased.FilesMapperHelper; +import de.ozgcloud.eingang.xdomea.XdomeaMessageData; -@Mapper +@Mapper(imports = FilesMapperHelper.class) interface XtaMessageMapper { + int VORGANG_NUMMER_SUFFIX_LENGTH = 4; @Mapping(target = "antragsteller", ignore = true) - @Mapping(target = "attachment", ignore = true) - @Mapping(target = "attachments", ignore = true) @Mapping(target = "formData", ignore = true) @Mapping(target = "id", ignore = true) - @Mapping(target = "numberOfAttachments", ignore = true) - @Mapping(target = "numberOfRepresentations", constant = "1") - @Mapping(target = "representation", ignore = true) - @Mapping(target = "representations", source = "messageFiles") @Mapping(target = "zustaendigeStelle", ignore = true) @Mapping(target = "header", source = "metaData") - FormData toFormData(XtaMessage message); + @Mapping(target = "numberOfAttachments", expression = "java(FilesMapperHelper.countAttachedFiles(xdomeaMessageData.attachments()))") + @Mapping(target = "numberOfRepresentations", dependsOn = "representations", expression = "java(getRepresentations(xdomeaMessageData).size())") + @Mapping(target = "representations", source = "xdomeaMessageData") + @Mapping(target = "representation", ignore = true) + @Mapping(target = "attachment", ignore = true) + FormData toFormData(XdomeaMessageData xdomeaMessageData, XtaMessageMetaData metaData, @Context VorgangNummerSupplier vorgangNummerSupplier); + + default List<IncomingFile> getRepresentations(XdomeaMessageData xdomeaMessageData) { + return Stream.concat( + Stream.of(xdomeaMessageData.metadataFile()), + xdomeaMessageData.representations().stream() + ).toList(); + } - @Mapping(target = "formEngineName", ignore = true) @Mapping(target = "formId", source = "messageType") @Mapping(target = "requestId", source = "messageId") + @Mapping(target = "vorgangNummer", expression = "java(vorgangNummerSupplier.get(VORGANG_NUMMER_SUFFIX_LENGTH))") @Mapping(target = "serviceKonto", ignore = true) @Mapping(target = "createdAt", source = "origin") @Mapping(target = "sender", constant = "XTA") - @Mapping(target = "formName", constant = "dFördermittelantrag") - FormHeader formHeaderFromMetaData(XtaMessageMetaData metaData); - - default IncomingFile toIncomingFile(XtaFile messageFile) { - if (Objects.nonNull(messageFile)) { - return IncomingFile.builder() - .name(messageFile.name()) - .contentType("application/zip") - .file(messageFile.file()) - .size(messageFile.file().length()) - .build(); - } - return null; - } + @Mapping(target = "formName", ignore = true) + @Mapping(target = "formEngineName", ignore = true) + FormHeader formHeaderFromMetaData(XtaMessageMetaData metaData, @Context VorgangNummerSupplier vorgangNummerSupplier); default String fromId(XtaMessageId id) { return id.toString(); 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 5da39aab1d30059a0e4577686a7427bc860f6278..4f59251706db33e1fe5d24ce333fb7f3a255a5a3 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 @@ -12,6 +12,9 @@ import java.util.stream.Stream; import javax.xml.namespace.QName; import javax.xml.transform.TransformerException; +import jakarta.validation.Valid; +import jakarta.xml.bind.JAXBElement; + import org.apache.commons.io.IOUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; @@ -44,8 +47,6 @@ import eu.osci.ws._2008._05.transport.MsgSelector; import eu.osci.ws._2008._05.transport.MsgStatusListType; import eu.osci.ws._2008._05.transport.ObjectFactory; import eu.osci.ws._2014._10.transport.MessageMetaData; -import jakarta.validation.Valid; -import jakarta.xml.bind.JAXBElement; import lombok.NonNull; import lombok.extern.log4j.Log4j2; 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 9e60b84b7ac4ba0dafc491ae1d80742a4d002d58..2341fbf6dc93899cb0c195ee6f09be52266c5c81 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,13 +4,14 @@ import java.util.Spliterators; import java.util.stream.Stream; import java.util.stream.StreamSupport; +import de.ozgcloud.eingang.common.vorgang.VorgangNummerSupplier; +import de.ozgcloud.eingang.xdomea.XdomeaMessageDataMapper; +import lombok.RequiredArgsConstructor; import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import de.ozgcloud.eingang.common.formdata.FormData; -import de.ozgcloud.eingang.common.formdata.FormHeader; -import de.ozgcloud.eingang.common.vorgang.VorgangNummerSupplier; import lombok.NonNull; import lombok.extern.log4j.Log4j2; @@ -18,8 +19,7 @@ import lombok.extern.log4j.Log4j2; @Log4j2 class XtaService { - static final String DFOERDERMITTELANTRAG_MESSAGE_TYPE = "Geschaeftsgang.Geschaeftsgang.0201"; - static final int VORGANG_NUMMER_SUFFIX_LENGTH = 4; + static final String XDOMEA_0201_MESSAGE_TYPE = "Geschaeftsgang.Geschaeftsgang.0201"; @Autowired private XtaRemoteService remoteService; @@ -27,9 +27,13 @@ class XtaService { private XtaMessageMapper mapper; @Autowired private VorgangNummerSupplier vorgangNummerSupplier; + @Autowired + private XdomeaMessageDataMapper xdomeaMessageDataMapper; + @Autowired + private XtaIncomingFilesMapper xtaIncomingFilesMapper; public Stream<FormData> getMessages() { - return createXtaMessageStream().filter(this::filterByMessageType).map(this::getFormData); + return createXtaMessageStream().filter(this::isSupportedMessageType).map(this::getFormData); } Stream<XtaMessageMetaData> createXtaMessageStream() { @@ -37,10 +41,8 @@ class XtaService { return StreamSupport.stream(Spliterators.spliteratorUnknownSize(iterator, 0), false); } - // filter criteria for dFoerdermittelantrag - // https://jira.mgm-tp.com/jira/browse/OZG-3659 - boolean filterByMessageType(XtaMessageMetaData metaData) { - if (StringUtils.equals(metaData.getMessageType(), DFOERDERMITTELANTRAG_MESSAGE_TYPE)) { + boolean isSupportedMessageType(XtaMessageMetaData metaData) { + if (StringUtils.equals(metaData.getMessageType(), XDOMEA_0201_MESSAGE_TYPE)) { return true; } @@ -50,16 +52,10 @@ class XtaService { public FormData getFormData(@NonNull XtaMessageMetaData metaData) { var msg = remoteService.getMessage(metaData.getMessageId()); - var formData = mapper.toFormData(msg.toBuilder().metaData(metaData).build()); - return updateHeader(formData); - } - - FormData updateHeader(FormData formData) { - return formData.toBuilder().header(setVorgangNummer(formData.getHeader())).build(); - } + var incomingFiles = xtaIncomingFilesMapper.toIncomingFiles(msg.getMessageFiles()); + var xdomeaMessageData = xdomeaMessageDataMapper.mapIncomingFilesToXdomeaMessageData(incomingFiles); - FormHeader setVorgangNummer(FormHeader formHeader) { - return formHeader.toBuilder().vorgangNummer(vorgangNummerSupplier.get(VORGANG_NUMMER_SUFFIX_LENGTH)).build(); + return mapper.toFormData(xdomeaMessageData, metaData, vorgangNummerSupplier); } public void acknowledgeReceive(@NonNull XtaMessageId messageId) { diff --git a/xta-adapter/src/main/resources/soapUiProjekt/XTA.zip b/xta-adapter/src/main/resources/soapUiProjekt/XTA.zip new file mode 100644 index 0000000000000000000000000000000000000000..8e60ba0bf6dab53dd22cad0cfd6f5372dae292e2 Binary files /dev/null and b/xta-adapter/src/main/resources/soapUiProjekt/XTA.zip differ diff --git a/xta-adapter/src/test/java/de/ozgcloud/eingang/xdomea/XdomeaMessageDataMapperTest.java b/xta-adapter/src/test/java/de/ozgcloud/eingang/xdomea/XdomeaMessageDataMapperTest.java new file mode 100644 index 0000000000000000000000000000000000000000..b061b1590bae4d357d79eec4f5eea866b314ae34 --- /dev/null +++ b/xta-adapter/src/test/java/de/ozgcloud/eingang/xdomea/XdomeaMessageDataMapperTest.java @@ -0,0 +1,179 @@ +package de.ozgcloud.eingang.xdomea; + +import static de.ozgcloud.eingang.xdomea.XdomeaMessageDataMapper.*; +import static org.assertj.core.api.Assertions.*; +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.Mockito.*; + +import java.util.List; +import java.util.stream.Stream; + +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 de.ozgcloud.eingang.common.errorhandling.TechnicalException; +import de.ozgcloud.eingang.common.formdata.IncomingFile; +import de.ozgcloud.eingang.common.formdata.IncomingFileTestFactory; + +class XdomeaMessageDataMapperTest { + + @Spy + @InjectMocks + XdomeaMessageDataMapper fileClassifier; + + @Mock + private XdomeaXMLValueReader valueReader; + + @DisplayName("find Xdomea XML file") + @Nested + class TestFindXdomeaXmlFile { + + private static final String FILE_NAME_WITHOUT_SUFFIX = "some-file-name.xml"; + private static final String FILE_NAME_WITH_SUFFIX = "some-file-name" + XDOMEA_0201_XML_FILE_NAME_SUFFIX; + + @DisplayName("should throw if not found") + @Test + void shouldThrowIfNotFound() { + var incomingFilesWithout = List.of(IncomingFileTestFactory.createWithName(FILE_NAME_WITHOUT_SUFFIX)); + + assertThatThrownBy(() -> fileClassifier.findXdomeaXMLFile(incomingFilesWithout)) + .isInstanceOf(TechnicalException.class); + } + + @DisplayName("should return if found") + @Test + void shouldReturnIfFound() { + var targetIncomingFile = IncomingFileTestFactory.createWithName(FILE_NAME_WITH_SUFFIX); + var incomingFilesWith = List.of( + IncomingFileTestFactory.createWithName(FILE_NAME_WITHOUT_SUFFIX), + targetIncomingFile + ); + + var primaryRepresentation = fileClassifier.findXdomeaXMLFile(incomingFilesWith); + + assertThat(primaryRepresentation).isEqualTo(targetIncomingFile); + } + } + + @DisplayName("find primary representation name") + @Nested + class TestFindPrimaryRepresentationName { + private static final String FILE_NAME_WITHOUT_XML_SUFFIX = "some-file-name.pdf"; + private static final String FILE_NAME_WITHOUT_XML_SUFFIX2 = "some-file-name.xml.pdf"; + private static final String FILE_NAME_WITH_XML_SUFFIX = "some-file-name.xml"; + private static final String FILE_NAME_WITH_XML_SUFFIX2 = "some-file-name.pdf.xml"; + + @DisplayName("should throw if no xml suffix") + @Test + void shouldThrowIfNoXmlSuffix() { + var listWithoutSuffix = List.of(FILE_NAME_WITHOUT_XML_SUFFIX, FILE_NAME_WITHOUT_XML_SUFFIX2); + + assertThrows(TechnicalException.class, () -> fileClassifier.findPrimaryRepresentationName(listWithoutSuffix)); + } + + @DisplayName("should return first with xml suffix") + @Test + void shouldReturnFirstWithXmlSuffix() { + var listWithSuffix = List.of(FILE_NAME_WITHOUT_XML_SUFFIX, FILE_NAME_WITH_XML_SUFFIX, FILE_NAME_WITHOUT_XML_SUFFIX2, + FILE_NAME_WITH_XML_SUFFIX2); + + var fileName = fileClassifier.findPrimaryRepresentationName(listWithSuffix); + + assertThat(fileName).isEqualTo(FILE_NAME_WITH_XML_SUFFIX); + } + } + + @DisplayName("classify attachments and representations") + @Nested + class TestClassifyAttachmentsAndRepresentations { + + private static final String XDOMEA_XML_NAME = "xdomea.xml"; + private static final String REPR_XML_NAME = "repr.xml"; + private static final String REPR_PDF_NAME = "repr.pdf"; + private static final String ATTATCHMENT_XML_NAME = "att.xml"; + private static final String ATTATCHMENT_PNG_NAME = "att.png"; + private static final String ATTATCHMENT_PDF_NAME = "att.pdf"; + + @Mock + private IncomingFile xdomeaXMLFile; + + private List<IncomingFile> incomingFileList; + + @BeforeEach + void mock() { + incomingFileList = Stream.of( + XDOMEA_XML_NAME, + REPR_XML_NAME, + REPR_PDF_NAME, + ATTATCHMENT_XML_NAME, + ATTATCHMENT_PNG_NAME, + ATTATCHMENT_PDF_NAME + ) + .map(IncomingFileTestFactory::createWithName) + .toList(); + doReturn(xdomeaXMLFile).when(fileClassifier).findXdomeaXMLFile(incomingFileList); + + when(xdomeaXMLFile.getName()).thenReturn(XDOMEA_XML_NAME); + + var representationFileNames = List.of(REPR_PDF_NAME, REPR_XML_NAME); + when(valueReader.readRepresentationFileNames(xdomeaXMLFile)).thenReturn(representationFileNames); + doReturn(REPR_XML_NAME).when(fileClassifier).findPrimaryRepresentationName(representationFileNames); + } + + @DisplayName("should contain xdomea metadata file") + @Test + void shouldContainXdomeaMetadataFile() { + var classification = doClassify(); + + var primaryDocument = classification.metadataFile(); + + assertThat(primaryDocument.getName()).isEqualTo(XDOMEA_XML_NAME); + } + + @DisplayName("should contain representations") + @Test + void shouldContainRepresentations() { + var classification = doClassify(); + + var resultRepresentationFileNames = classification.representations().stream() + .map(IncomingFile::getName) + .toList(); + // Expect that the primary representation xml file is move to the first position + assertThat(resultRepresentationFileNames).isEqualTo(List.of(REPR_XML_NAME, REPR_PDF_NAME)); + } + + @DisplayName("should contain attachments") + @Test + void shouldContainAttachments() { + var classification = doClassify(); + + var resultAttachmentFileNames = classification.attachments() + .getFirst() + .getFiles().stream() + .map(IncomingFile::getName) + .toList(); + assertThat(resultAttachmentFileNames).isEqualTo(List.of(ATTATCHMENT_XML_NAME, ATTATCHMENT_PNG_NAME, ATTATCHMENT_PDF_NAME)); + } + + @DisplayName("should have attachment group name") + @Test + void shouldHaveAttachmentGroupName() { + var classification = doClassify(); + + var resultAttachmentGroupName = classification.attachments() + .getFirst() + .getName(); + assertThat(resultAttachmentGroupName).isEqualTo(ATTACHMENT_GROUP_NAME); + } + + private XdomeaMessageData doClassify() { + return fileClassifier.mapIncomingFilesToXdomeaMessageData(incomingFileList); + } + } + +} diff --git a/xta-adapter/src/test/java/de/ozgcloud/eingang/xdomea/XdomeaMessageDataTestFactory.java b/xta-adapter/src/test/java/de/ozgcloud/eingang/xdomea/XdomeaMessageDataTestFactory.java new file mode 100644 index 0000000000000000000000000000000000000000..90a659b8ddddb9cbef12e8c54da9f33ee213ab74 --- /dev/null +++ b/xta-adapter/src/test/java/de/ozgcloud/eingang/xdomea/XdomeaMessageDataTestFactory.java @@ -0,0 +1,19 @@ +package de.ozgcloud.eingang.xdomea; + +import java.util.List; + +import de.ozgcloud.eingang.common.formdata.IncomingFileGroup; +import de.ozgcloud.eingang.common.formdata.IncomingFileTestFactory; + +public class XdomeaMessageDataTestFactory { + public static XdomeaMessageData create() { + return createBuilder().build(); + } + + public static XdomeaMessageData.XdomeaMessageDataBuilder createBuilder() { + return XdomeaMessageData.builder() + .metadataFile(IncomingFileTestFactory.createBuilder().name("xdomea-primary-document.xml").build()) + .representations(List.of(IncomingFileTestFactory.create())) + .attachment(IncomingFileGroup.builder().file(IncomingFileTestFactory.create()).build()); + } +} diff --git a/xta-adapter/src/test/java/de/ozgcloud/eingang/xdomea/XdomeaXMLValueReaderTest.java b/xta-adapter/src/test/java/de/ozgcloud/eingang/xdomea/XdomeaXMLValueReaderTest.java new file mode 100644 index 0000000000000000000000000000000000000000..01f474a3112f356f02d19157029a87cc636c441d --- /dev/null +++ b/xta-adapter/src/test/java/de/ozgcloud/eingang/xdomea/XdomeaXMLValueReaderTest.java @@ -0,0 +1,58 @@ +package de.ozgcloud.eingang.xdomea; + +import static org.assertj.core.api.Assertions.*; +import static org.mockito.Mockito.*; + +import java.nio.charset.StandardCharsets; +import java.util.List; + +import org.apache.commons.io.IOUtils; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.Spy; + +import de.ozgcloud.common.test.TestUtils; +import de.ozgcloud.eingang.common.formdata.IncomingFile; +import lombok.SneakyThrows; + +class XdomeaXMLValueReaderTest { + private static final String XML_FILE_NAME = "file.xml"; + private static final String PDF_FILE_NAME = "file.pdf"; + + @Spy + @InjectMocks + private XdomeaXMLValueReader valueReader; + + @DisplayName("read representation file names") + @Nested + class TestReadRepresentationFileNames { + + @Mock + IncomingFile incomingXmlFile; + + @DisplayName("should find 'Dateiname' elements in MSR mantelantrag") + @ParameterizedTest + @ValueSource(strings = { + "xdomea/mantelantrag_Geschaeftsgang.Geschaeftsgang.0201.xml", + "xdomea/dfoerdermittel_Geschaeftsgang.Geschaeftsgang.0201.xml" + }) + @SneakyThrows + void shouldFindDateinameElements(String antragXMLFilename) { + var xmlString = TestUtils.loadTextFile( + antragXMLFilename, + XML_FILE_NAME, + PDF_FILE_NAME); + when(incomingXmlFile.getContentStream()).thenReturn(IOUtils.toInputStream(xmlString, StandardCharsets.UTF_8)); + + var names = valueReader.readRepresentationFileNames(incomingXmlFile); + + assertThat(names).isEqualTo(List.of(XML_FILE_NAME, PDF_FILE_NAME)); + } + + } + +} diff --git a/xta-adapter/src/test/java/de/ozgcloud/eingang/xta/FormHeaderTestFactory.java b/xta-adapter/src/test/java/de/ozgcloud/eingang/xta/FormHeaderTestFactory.java index db83159ccffc9185959569982fc9d09c7479a6fe..acd02b8efce3f09542c8dc5c748850027ad27072 100644 --- a/xta-adapter/src/test/java/de/ozgcloud/eingang/xta/FormHeaderTestFactory.java +++ b/xta-adapter/src/test/java/de/ozgcloud/eingang/xta/FormHeaderTestFactory.java @@ -1,11 +1,12 @@ package de.ozgcloud.eingang.xta; import de.ozgcloud.eingang.common.formdata.FormHeader; -import de.ozgcloud.eingang.common.formdata.FormHeader.FormHeaderBuilder;; +import de.ozgcloud.eingang.common.formdata.FormHeader.FormHeaderBuilder; public class FormHeaderTestFactory { - private static final String FORM_NAME = "dFördermittelantrag"; + private static final String FORM_NAME = "xdomea"; + static final String VORGANGNUMMER = "vorgangNummer"; static FormHeader create() { return createBuilder().build(); @@ -15,6 +16,7 @@ public class FormHeaderTestFactory { return FormHeader.builder() .sender("XTA") .requestId(XtaMessageTestFactory.MESSAGE_ID.toString()) + .vorgangNummer(VORGANGNUMMER) .formName(FORM_NAME) .formId(XtaMessageMetaDataTestFactory.MESSAGE_TYPE) .createdAt(XtaMessageMetaDataTestFactory.ORIGIN); diff --git a/xta-adapter/src/test/java/de/ozgcloud/eingang/xta/XtaApplicationTest.java b/xta-adapter/src/test/java/de/ozgcloud/eingang/xta/XtaApplicationTest.java index 59bddcf63df7c9135a753a6ee4aab49a375bd087..8e2d830f342905d66d07dca69cd304b92bef142c 100644 --- a/xta-adapter/src/test/java/de/ozgcloud/eingang/xta/XtaApplicationTest.java +++ b/xta-adapter/src/test/java/de/ozgcloud/eingang/xta/XtaApplicationTest.java @@ -1,32 +1,21 @@ package de.ozgcloud.eingang.xta; -import static org.assertj.core.api.Assertions.assertThat; -import static org.junit.Assert.*; +import static org.junit.jupiter.api.Assertions.*; import org.junit.jupiter.api.Test; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.test.context.ActiveProfiles; import de.ozgcloud.eingang.Application; -import de.ozgcloud.eingang.semantik.enginebased.EngineBasedSemantikAdapter; -import de.ozgcloud.eingang.semantik.enginebased.xta.XtaEngineBasedAdapter; @ActiveProfiles({ "local", "itcase" }) @SpringBootTest(classes = Application.class) class XtaApplicationTest { - @Autowired - private EngineBasedSemantikAdapter engineBasedAdapter; - @Test void startup() { // should start without exception; assertTrue(true); } - @Test - void shouldHaveEngineBasedAdapter() { - assertThat(engineBasedAdapter).isInstanceOf(XtaEngineBasedAdapter.class); - } } diff --git a/xta-adapter/src/test/java/de/ozgcloud/eingang/xta/XtaFileTestFactory.java b/xta-adapter/src/test/java/de/ozgcloud/eingang/xta/XtaFileTestFactory.java index f6eaca430bafa55daa30defef2ca846a3f91a07a..5512656128e6245be33f1f274e87f536637914ca 100644 --- a/xta-adapter/src/test/java/de/ozgcloud/eingang/xta/XtaFileTestFactory.java +++ b/xta-adapter/src/test/java/de/ozgcloud/eingang/xta/XtaFileTestFactory.java @@ -13,18 +13,22 @@ class XtaFileTestFactory { static final String NAME = "Test_File"; static final String CONTENT = "slkafj3jifsdasx"; + static final String ZIP_CONTENT_TYPE = "application/zip"; static XtaFile create() { return createBuilder().build(); } static XtaFile.XtaFileBuilder createBuilder() { - return XtaFile.builder().name(NAME).file(createFile()); + return XtaFile.builder() + .name(NAME) + .contentType(ZIP_CONTENT_TYPE) + .file(createFile()); } @SneakyThrows private static File createFile() { - File tFile = File.createTempFile("test", "txt"); + File tFile = File.createTempFile("test", "zip"); tFile.deleteOnExit(); FileUtils.write(tFile, CONTENT, StandardCharsets.UTF_8); diff --git a/xta-adapter/src/test/java/de/ozgcloud/eingang/xta/XtaITCase.java b/xta-adapter/src/test/java/de/ozgcloud/eingang/xta/XtaITCase.java index beb10f64917e4923553562d5ffa19298e4a58db8..8f22e393ae6f75b7bf19a48b6c682e8476899b6e 100644 --- a/xta-adapter/src/test/java/de/ozgcloud/eingang/xta/XtaITCase.java +++ b/xta-adapter/src/test/java/de/ozgcloud/eingang/xta/XtaITCase.java @@ -44,7 +44,8 @@ class XtaITCase { when(remoteService.getMessage(any(XtaMessageId.class))).thenReturn( XtaMessageTestFactory.createBuilder() .clearMessageFiles() - .messageFile(XtaFileTestFactory.withFileContent(TestUtils.loadFile("test_content.zip"), "test_content.zip")) + .messageFile(XtaFileTestFactory.withFileContent(TestUtils.loadFile("xdomea/dfoerdermittel_without_anlage.zip"), + "dfoerdermittel_without_anlage.zip")) .build()); } @@ -63,12 +64,21 @@ class XtaITCase { } @Test - void shouldSend4Representations() { + void shouldSend3Representations() { runner.onApplicationEvent(null); verify(vorgangRemoteService).createVorgang(formDataCaptor.capture(), any(), any()); - assertThat(formDataCaptor.getValue().getNumberOfRepresentations()).isEqualTo(4); - assertThat(formDataCaptor.getValue().getRepresentations()).hasSize(4); + assertThat(formDataCaptor.getValue().getRepresentations()).hasSize(3); + assertThat(formDataCaptor.getValue().getNumberOfRepresentations()).isEqualTo(3); + } + + @Test + void shouldSendNoAttachments() { + runner.onApplicationEvent(null); + + verify(vorgangRemoteService).createVorgang(formDataCaptor.capture(), any(), any()); + assertThat(formDataCaptor.getValue().getAttachments()).isEmpty(); + assertThat(formDataCaptor.getValue().getNumberOfAttachments()).isZero(); } @Test @@ -115,4 +125,4 @@ class ActivateXTARunnerConfig { XtaRunner xtaRunner() { return new XtaRunner(); } -} \ No newline at end of file +} 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 new file mode 100644 index 0000000000000000000000000000000000000000..da3cdcceeefb8b0f298fb7166bd200fc28b335bc --- /dev/null +++ b/xta-adapter/src/test/java/de/ozgcloud/eingang/xta/XtaIncomingFilesMapperTest.java @@ -0,0 +1,152 @@ +/* + * Copyright (C) 2024 Das Land Schleswig-Holstein vertreten durch das + * Ministerium für Energiewende, Klimaschutz, Umwelt und Natur + * Zentrales IT-Management + * + * Lizenziert unter der EUPL, Version 1.2 oder - sobald + * diese von der Europäischen Kommission genehmigt wurden - + * Folgeversionen der EUPL ("Lizenz"); + * Sie dürfen dieses Werk ausschließlich gemäß + * dieser Lizenz nutzen. + * Eine Kopie der Lizenz finden Sie hier: + * + * https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 + * + * Sofern nicht durch anwendbare Rechtsvorschriften + * gefordert oder in schriftlicher Form vereinbart, wird + * die unter der Lizenz verbreitete Software "so wie sie + * ist", OHNE JEGLICHE GEWÄHRLEISTUNG ODER BEDINGUNGEN - + * ausdrücklich oder stillschweigend - verbreitet. + * Die sprachspezifischen Genehmigungen und Beschränkungen + * unter der Lizenz sind dem Lizenztext zu entnehmen. + */ + +package de.ozgcloud.eingang.xta; + +import static org.assertj.core.api.Assertions.*; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.*; + +import de.ozgcloud.eingang.common.formdata.IncomingFile; +import de.ozgcloud.eingang.common.formdata.IncomingFileTestFactory; +import de.ozgcloud.eingang.common.zip.ZipAttachmentReader; +import lombok.SneakyThrows; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; +import org.mockito.MockedStatic; +import org.mockito.Mockito; +import org.mockito.Spy; + +import java.io.InputStream; +import java.util.List; +import java.util.stream.IntStream; +import java.util.stream.Stream; + +class XtaIncomingFilesMapperTest { + @Spy + private XtaIncomingFilesMapper mapper = new XtaIncomingFilesMapper(); + + private static final String ZIP_CONTENT_TYPE = "application/zip"; + + @Nested + class TestToIncomingFiles { + + @Test + void shouldMapToIncomingFiles() { + var xtaFile = XtaFileTestFactory.create(); + var incomingFile = IncomingFileTestFactory.create(); + when(mapper.toIncomingFile(xtaFile)).thenReturn(incomingFile); + when(mapper.extractZip(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); + } + + @Test + void shouldHandleMissingMessageFile() { + var fileGroup = mapper.toIncomingFiles(null); + + assertThat(fileGroup).isEmpty(); + } + } + + @Nested + class ToIncomingFile { + @Test + void shouldHaveMessageFile() { + var inFile = mapper.toIncomingFile(XtaFileTestFactory.create()); + + assertThat(inFile.getContentStream()).isNotNull(); + } + + @Test + void shouldHaveFileName() { + var inFile = mapper.toIncomingFile(XtaFileTestFactory.create()); + + assertThat(inFile.getName()).isEqualTo(XtaFileTestFactory.NAME); + } + + @Test + void shouldHaveZipContentType() { + var inFile = mapper.toIncomingFile(XtaFileTestFactory.create()); + + assertThat(inFile.getContentType()).isEqualTo(XtaFileTestFactory.ZIP_CONTENT_TYPE); + } + + @Test + void shouldHaveSize() { + var inFile = mapper.toIncomingFile(XtaFileTestFactory.create()); + + assertThat(inFile.getSize()).isEqualTo(XtaFileTestFactory.CONTENT.length()); + } + } + + @Nested + class TestExtractZip { + + @Test + void shouldExtractZipFiles() { + try (var zipAttachment = Mockito.mockStatic(ZipAttachmentReader.class)) { + var zipAttachmentReaderMock = initZipRepresentationMocks(zipAttachment); + + var extractedFiles = mapper.extractZip(createTestIncomingFile()).toList(); + + verify(zipAttachmentReaderMock).readContent(); + assertThat(extractedFiles).hasSize(2); + } + } + + IncomingFile createTestIncomingFile() { + return IncomingFileTestFactory.createBuilder() + .name("attachments.zip") + .contentType(ZIP_CONTENT_TYPE) + .build(); + } + + @Test + void shouldIgnoreNonZipFiles() { + var incomingFile = IncomingFileTestFactory.create(); + + var extractedFiles = mapper.extractZip(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(); + } + + @SneakyThrows + private static ZipAttachmentReader initZipRepresentationMocks(MockedStatic<ZipAttachmentReader> zipAttachmentMock) { + var contentEntries = IntStream.range(0, 2).boxed().map(i -> IncomingFileTestFactory.createBuilder().name(i.toString()).build()).toList(); + ZipAttachmentReader mock = when(mock(ZipAttachmentReader.class).readContent()).thenReturn(contentEntries).getMock(); + zipAttachmentMock.when(() -> ZipAttachmentReader.from(any(InputStream.class), any())).thenReturn(mock); + return mock; + } +} 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 7655eb0d5a3253758a940dba565a2bedb3c6c8fe..b9bcda822a302872474e1c4341cbe08b11675b99 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 @@ -1,95 +1,81 @@ package de.ozgcloud.eingang.xta; +import static de.ozgcloud.eingang.xta.XtaMessageMapper.*; import static org.assertj.core.api.Assertions.*; -import static org.mockito.ArgumentMatchers.*; import static org.mockito.Mockito.*; +import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; import org.mapstruct.factory.Mappers; import org.mockito.InjectMocks; +import org.mockito.Mock; import org.mockito.Spy; +import de.ozgcloud.eingang.common.formdata.FormData; +import de.ozgcloud.eingang.common.vorgang.VorgangNummerSupplier; +import de.ozgcloud.eingang.xdomea.XdomeaMessageDataTestFactory; +import de.ozgcloud.eingang.xdomea.XdomeaMessageData; + class XtaMessageMapperTest { @Spy @InjectMocks private XtaMessageMapper mapper = Mappers.getMapper(XtaMessageMapper.class); + @Mock + private VorgangNummerSupplier vorgangNummerSupplier; + @Nested class TestToFormData { - @Test - void shouldMapAllToForm() { - var formData = mapper.toFormData(XtaMessageTestFactory.create()); + private XtaMessageMetaData xtaMessageMetaData; + private XdomeaMessageData xdomeaMessageData; - assertThat(formData).usingRecursiveComparison().ignoringFields("id", "representations") - .isEqualTo(FormDataTestFactory.create()); + @BeforeEach + void mock() { + xtaMessageMetaData = XtaMessageMetaDataTestFactory.create(); + xdomeaMessageData = XdomeaMessageDataTestFactory.create(); + when(vorgangNummerSupplier.get(VORGANG_NUMMER_SUFFIX_LENGTH)).thenReturn(FormHeaderTestFactory.VORGANGNUMMER); } @Test - void shouldHaveMessageFileAsRepresentation() { - var formData = mapper.toFormData(XtaMessageTestFactory.create()); + void shouldMapRepresentations() { + var formData = doMapping(); - assertThat(formData.getRepresentations()).hasSize(1); + assertThat(formData.getRepresentations()).containsExactly(xdomeaMessageData.metadataFile(), xdomeaMessageData.representations().getFirst()); } @Test - void shouldCallToIncomingFile() { - XtaMessage message = XtaMessageTestFactory.create(); - - mapper.toFormData(message); + void shouldSetNumberOfAttachments() { + var formData = doMapping(); - verify(mapper).toIncomingFile(notNull()); + assertThat(formData.getNumberOfAttachments()).isEqualTo(1); } - @Nested - class ToFormHeader { - @Test - void shouldMapToFormHeader() { - var mapped = mapper.formHeaderFromMetaData(XtaMessageMetaDataTestFactory.create()); + @Test + void shouldSetNumberOfRepresentations() { + var formData = doMapping(); - assertThat(mapped).usingRecursiveComparison().isEqualTo(FormHeaderTestFactory.create()); - } + assertThat(formData.getNumberOfRepresentations()).isEqualTo(2); } - @Nested - class ToIncomingFile { - @Test - void shouldHaveMessageFile() { - var inFile = mapper.toIncomingFile(XtaFileTestFactory.create()); - - assertThat(inFile.getContentStream()).isNotNull(); - } - - @Test - void shouldHaveFileName() { - var inFile = mapper.toIncomingFile(XtaFileTestFactory.create()); - - assertThat(inFile.getName()).isEqualTo(XtaFileTestFactory.NAME); - } - - @Test - void shouldHaveZipContentType() { - var inFile = mapper.toIncomingFile(XtaFileTestFactory.create()); - - assertThat(inFile.getContentType()).isEqualTo("application/zip"); - } - - @Test - void shouldHaveSize() { - var inFile = mapper.toIncomingFile(XtaFileTestFactory.create()); + @Test + void shouldMapAttachments() { + var formData = doMapping(); - assertThat(inFile.getSize()).isEqualTo(XtaFileTestFactory.CONTENT.length()); - } + assertThat(formData.getAttachments()).isEqualTo(xdomeaMessageData.attachments()); + } - @Test - void shouldHandleMissingMessageFile() { - var fileGroup = mapper.toIncomingFile(null); + @Test + void shouldMapVorgangNummer() { + var formData = doMapping(); - assertThat(fileGroup).isNull(); - } + assertThat(formData.getHeader().getVorgangNummer()).isEqualTo(FormHeaderTestFactory.VORGANGNUMMER); } + private FormData doMapping() { + return mapper.toFormData(xdomeaMessageData, xtaMessageMetaData, vorgangNummerSupplier); + } } } diff --git a/xta-adapter/src/test/java/de/ozgcloud/eingang/xta/XtaRemoteServiceConfigurationTest.java b/xta-adapter/src/test/java/de/ozgcloud/eingang/xta/XtaRemoteServiceConfigurationTest.java index cb5c3f846497e9e8d9c2e39dc1fb58e4f14144da..59d354ecb7c21690e7656712e51c7c5bc56428a3 100644 --- a/xta-adapter/src/test/java/de/ozgcloud/eingang/xta/XtaRemoteServiceConfigurationTest.java +++ b/xta-adapter/src/test/java/de/ozgcloud/eingang/xta/XtaRemoteServiceConfigurationTest.java @@ -3,11 +3,13 @@ package de.ozgcloud.eingang.xta; import static org.assertj.core.api.Assertions.*; import org.junit.jupiter.api.Test; +import org.mockito.InjectMocks; import org.mockito.Spy; class XtaRemoteServiceConfigurationTest { @Spy + @InjectMocks XtaRemoteServiceConfiguration configuration; @Test diff --git a/xta-adapter/src/test/java/de/ozgcloud/eingang/xta/XtaRemoteServiceTest.java b/xta-adapter/src/test/java/de/ozgcloud/eingang/xta/XtaRemoteServiceTest.java index dd6b6d41529a9446a78b76bdf8ccd2bf404a3cb0..a1c37d0b970039056a996ab875c6476a60abd4c5 100644 --- a/xta-adapter/src/test/java/de/ozgcloud/eingang/xta/XtaRemoteServiceTest.java +++ b/xta-adapter/src/test/java/de/ozgcloud/eingang/xta/XtaRemoteServiceTest.java @@ -114,7 +114,7 @@ class XtaRemoteServiceTest { } @Test - void hosuldReturnMessageWithFile() { + void shouldReturnMessageWithFile() { var message = service.getMessage(XtaMessageTestFactory.MESSAGE_ID); assertThat(message.getMessageFiles()).hasSize(1).contains(file); diff --git a/xta-adapter/src/test/java/de/ozgcloud/eingang/xta/XtaServiceITCase.java b/xta-adapter/src/test/java/de/ozgcloud/eingang/xta/XtaServiceITCase.java index 3f25039dd3c66356a1727d80ea208381fc0e03b4..cfc4776f0dd29bdd3a0b85c9236832368a863065 100644 --- a/xta-adapter/src/test/java/de/ozgcloud/eingang/xta/XtaServiceITCase.java +++ b/xta-adapter/src/test/java/de/ozgcloud/eingang/xta/XtaServiceITCase.java @@ -18,8 +18,6 @@ import org.springframework.boot.test.context.SpringBootTest; import org.springframework.test.context.ActiveProfiles; import de.ozgcloud.eingang.Application; -import de.ozgcloud.eingang.semantik.enginebased.EngineBasedSemantikAdapter; -import de.ozgcloud.eingang.semantik.formbased.FormBasedSemantikAdapter; import lombok.SneakyThrows; import okhttp3.mockwebserver.MockWebServer; @@ -37,12 +35,6 @@ class XtaServiceITCase { @Autowired private XtaService xtaService; - @Autowired - private EngineBasedSemantikAdapter engineBasedAdapter; - - @Autowired - private FormBasedSemantikAdapter formBasedAdapter; - @Autowired private XtaProperties properties; @@ -89,13 +81,16 @@ class XtaServiceITCase { @Test void shouldUnzipCorrectNumberOfRepresentations() { var firstFormData = xtaService.getMessages().toList().getFirst(); - assertNotNull(firstFormData); - firstFormData = engineBasedAdapter.parseFormData(firstFormData); - firstFormData = formBasedAdapter.parseFormData(firstFormData); + assertThat(firstFormData.getRepresentations()).hasSize(3); + assertThat(firstFormData.getNumberOfRepresentations()).isEqualTo(3); + } + @DisplayName("should unzip correct number of attachments") + @Test + void shouldUnzipCorrectNumberOfAttachments() { + var firstFormData = xtaService.getMessages().toList().getFirst(); - // Expect that there are 3 files in attachment.zip and that the zip itself is a representation - assertThat(firstFormData.getNumberOfRepresentations()).isEqualTo(4); + assertThat(firstFormData.getAttachments()).isEmpty(); } } 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 d1fc3de86803ba5fc9c49a574011b41adf8e3be0..75a00a6610db89ffeaed0ba620d4676038fda296 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 @@ -4,9 +4,9 @@ import static org.assertj.core.api.Assertions.*; import static org.mockito.ArgumentMatchers.*; import static org.mockito.Mockito.*; +import java.util.List; import java.util.stream.Stream; -import org.assertj.core.api.Assertions; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; @@ -16,8 +16,11 @@ import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.Spy; -import de.ozgcloud.eingang.common.formdata.FormData; +import de.ozgcloud.eingang.common.formdata.IncomingFileTestFactory; import de.ozgcloud.eingang.common.vorgang.VorgangNummerSupplier; +import de.ozgcloud.eingang.xdomea.XdomeaMessageData; +import de.ozgcloud.eingang.xdomea.XdomeaMessageDataTestFactory; +import de.ozgcloud.eingang.xdomea.XdomeaMessageDataMapper; class XtaServiceTest { @@ -34,12 +37,17 @@ class XtaServiceTest { @Mock private VorgangNummerSupplier vorgangNummerSupplier; + @Mock + private XtaIncomingFilesMapper incomingFilesMapper; + + @Mock + private XdomeaMessageDataMapper xdomeaMessageDataMapper; + @Nested class TestGetMessagesAsFormData { - private XtaMessageMetaDatasAndHeader metaData = XtaMessageMetaDatasAndHeaderTestFactory.create(); - private XtaMessageMetaData messageMetaData = XtaMessageMetaDataTestFactory.create(); - private XtaMessage message = XtaMessageTestFactory.create(); + private final XtaMessageMetaData messageMetaData = XtaMessageMetaDataTestFactory.create(); + private final XtaMessage message = XtaMessageTestFactory.create(); @BeforeEach void setup() { @@ -55,19 +63,17 @@ class XtaServiceTest { @Test void shouldCallFilterByMessageType() { - when(mapper.toFormData(any())).thenReturn(FormDataTestFactory.create()); - when(remoteService.getMessage(any(XtaMessageId.class))).thenReturn(message); + setupMocks(); service.getMessages().toList(); - verify(service).filterByMessageType(messageMetaData); + verify(service).isSupportedMessageType(messageMetaData); } @Test void shouldCallGetFormData() { - when(mapper.toFormData(any())).thenReturn(FormDataTestFactory.create()); - when(remoteService.getMessage(any(XtaMessageId.class))).thenReturn(message); - doReturn(true).when(service).filterByMessageType(messageMetaData); + setupMocks(); + doReturn(true).when(service).isSupportedMessageType(messageMetaData); service.getMessages().toList(); @@ -76,51 +82,64 @@ class XtaServiceTest { @Test void shouldNotCallGetFormData() { - doReturn(false).when(service).filterByMessageType(messageMetaData); + doReturn(false).when(service).isSupportedMessageType(messageMetaData); service.getMessages().toList(); verify(service, never()).getFormData(any()); } + + private void setupMocks() { + var testFormData = FormDataTestFactory.create(); + when(mapper.toFormData(any(), any(), eq(vorgangNummerSupplier))).thenReturn(testFormData); + when(remoteService.getMessage(any(XtaMessageId.class))).thenReturn(message); + } } @Nested - class TestFilterByMessageType { + class TestIsSupportedMessageType { @Test void shouldAcceptDFoerdermittel() { var metaDataDFoerder = XtaMessageMetaDataTestFactory.create(); - assertThat(service.filterByMessageType(metaDataDFoerder)).isTrue(); + assertThat(service.isSupportedMessageType(metaDataDFoerder)).isTrue(); } @Test void shouldNotAcceptOtherMessageType() { var metaDataDFoerder = XtaMessageMetaDataTestFactory.createBuilder().messageType(MESSAGE_TYPE_OTHER).build(); - assertThat(service.filterByMessageType(metaDataDFoerder)).isFalse(); + assertThat(service.isSupportedMessageType(metaDataDFoerder)).isFalse(); } } @Nested class TestGetFormData { - private XtaMessage message = XtaMessageTestFactory.create(); + private XtaMessage message; + private XdomeaMessageData classification; + + @Captor + private ArgumentCaptor<XtaMessageMetaData> messageMetaDataCaptor; @Captor - private ArgumentCaptor<XtaMessage> messageCaptor; - @Mock - private FormData formData; + private ArgumentCaptor<XdomeaMessageData> classificationCaptor; @BeforeEach void init() { + message = XtaMessageTestFactory.create(); when(remoteService.getMessage(any(XtaMessageId.class))).thenReturn(message); + + classification = XdomeaMessageDataTestFactory.create(); + var incomingFiles = List.of(IncomingFileTestFactory.create(), IncomingFileTestFactory.create()); + when(incomingFilesMapper.toIncomingFiles(message.getMessageFiles())).thenReturn(incomingFiles); + classification = XdomeaMessageDataTestFactory.create(); + when(xdomeaMessageDataMapper.mapIncomingFilesToXdomeaMessageData(incomingFiles)).thenReturn(classification); } @Test void shouldCallRemoteService() { - doReturn(formData).when(service).updateHeader(any()); - service.getFormData(XtaMessageMetaDataTestFactory.create()); verify(remoteService).getMessage(XtaMessageTestFactory.MESSAGE_ID); @@ -128,29 +147,26 @@ class XtaServiceTest { @Test void shouldCallMapper() { - doReturn(formData).when(service).updateHeader(any()); - service.getFormData(XtaMessageMetaDataTestFactory.create()); - verify(mapper).toFormData(any()); + verify(mapper).toFormData(any(), any(), eq(vorgangNummerSupplier)); } @Test void shouldHaveMetaData() { - doReturn(formData).when(service).updateHeader(any()); XtaMessageMetaData metaData = XtaMessageMetaDataTestFactory.create(); service.getFormData(metaData); - verify(mapper).toFormData(messageCaptor.capture()); - assertThat(messageCaptor.getValue().getMetaData()).isNotNull().isEqualTo(metaData); + verify(mapper).toFormData(classificationCaptor.capture(), messageMetaDataCaptor.capture(), eq(vorgangNummerSupplier)); + assertThat(messageMetaDataCaptor.getValue()).isEqualTo(metaData); + assertThat(classificationCaptor.getValue()).isEqualTo(classification); } @Test void shouldReturnMappedResult() { var mapped = FormDataTestFactory.create(); - when(mapper.toFormData(any())).thenReturn(mapped); - doReturn(mapped).when(service).updateHeader(any()); + when(mapper.toFormData(any(), any(), eq(vorgangNummerSupplier))).thenReturn(mapped); var result = service.getFormData(XtaMessageMetaDataTestFactory.create()); @@ -158,50 +174,6 @@ class XtaServiceTest { } } - @Nested - class TestUpdateHeader { - - @Test - void shouldCallSetVorgangNummer() { - var formData = FormDataTestFactory.create(); - - service.updateHeader(formData); - - verify(service).setVorgangNummer(formData.getHeader()); - } - - @Test - void shouldSetUpdatedHeader() { - var updatedHeader = FormHeaderTestFactory.create(); - doReturn(updatedHeader).when(service).setVorgangNummer(any()); - - var result = service.updateHeader(FormDataTestFactory.create()); - - Assertions.assertThat(result.getHeader()).isSameAs(updatedHeader); - } - } - - @Nested - class TestSetVorgangNummer { - - @Test - void shouldCallVorgangNummerSupplier() { - service.setVorgangNummer(FormHeaderTestFactory.create()); - - verify(vorgangNummerSupplier).get(XtaService.VORGANG_NUMMER_SUFFIX_LENGTH); - } - - @Test - void shouldSetVorgangNummer() { - var vorgangNummer = "vorgang-1"; - when(vorgangNummerSupplier.get(anyInt())).thenReturn(vorgangNummer); - - var result = service.setVorgangNummer(FormHeaderTestFactory.create()); - - assertThat(result.getVorgangNummer()).isEqualTo(vorgangNummer); - } - } - @Nested class TestAcknowledgeReceive { diff --git a/xta-adapter/src/test/resources/test_content.zip b/xta-adapter/src/test/resources/test_content.zip deleted file mode 100644 index e2c9e434c49cf52a8d0840b1a25dcc52615df04c..0000000000000000000000000000000000000000 Binary files a/xta-adapter/src/test/resources/test_content.zip and /dev/null differ diff --git a/xta-adapter/src/test/resources/xdomea/dfoerdermittel_Geschaeftsgang.Geschaeftsgang.0201.xml b/xta-adapter/src/test/resources/xdomea/dfoerdermittel_Geschaeftsgang.Geschaeftsgang.0201.xml new file mode 100644 index 0000000000000000000000000000000000000000..28200a104f3cb7ded5851105ad2d9fd80034bc3c --- /dev/null +++ b/xta-adapter/src/test/resources/xdomea/dfoerdermittel_Geschaeftsgang.Geschaeftsgang.0201.xml @@ -0,0 +1,107 @@ +<?xml version="1.0" encoding="utf-8"?> +<Geschaeftsgang.Geschaeftsgang.0201 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xsi:schemaLocation="urn:xoev-de:xdomea:schema:2.4.0 xdomea-Nachrichten-VBS.xsd" xmlns="urn:xoev-de:xdomea:schema:2.4.0"> + <Kopf> + <ProzessID>b42b7984-279c-4260-8b48-c0389555608c</ProzessID> + <Nachrichtentyp listURI="urn:xoev-de:xdomea:codeliste:nachrichtentyp" listVersionID="1.0"> + <code xmlns="">0201</code> + </Nachrichtentyp> + <Erstellungszeitpunkt>2024-04-22T16:14:18.1885313+02:00</Erstellungszeitpunkt> + <Absender> + <Behoerdenkennung> + <Kennung listURI="" listVersionID=""> + <code xmlns="">010200200000</code> + </Kennung> + <Praefix listURI="" listVersionID=""> + <code xmlns="">gad</code> + </Praefix> + </Behoerdenkennung> + </Absender> + <Empfaenger> + <Behoerdenkennung> + <Kennung listURI="" listVersionID=""> + <code xmlns="">dev-environment@ozg-cloud.de</code> + </Kennung> + <Praefix listURI="" listVersionID=""> + <code xmlns="">gae</code> + </Praefix> + </Behoerdenkennung> + </Empfaenger> + <SendendesSystem> + <InstanzID>HH_dFoerdermittelantrag</InstanzID> + <Produktname>dFoerdermittelantrag</Produktname> + <Version>2.1.999.0</Version> + </SendendesSystem> + <EmpfangsbestaetigungAnInitiator>false</EmpfangsbestaetigungAnInitiator> + <EmpfangsbestaetigungAnVorgaenger>false</EmpfangsbestaetigungAnVorgaenger> + </Kopf> + <Hauptobjekt> + <Dokument> + <Identifikation> + <ID>0e7734d8-bf3f-4f8d-9568-3791abf8fe44</ID> + </Identifikation> + <AllgemeineMetadaten> + <Betreff>Testantrag für die OZG-Cloud</Betreff> + <Kennzeichen>08dc497a-f1d4-412d-80ca-4f58405dc83e</Kennzeichen> + </AllgemeineMetadaten> + <Version> + <Nummer>1</Nummer> + <Format> + <Name listURI="urn:xoev-de:xdomea:codeliste:dateiformat" listVersionID="1.0" xsi:type="DateiformatCodeType"> + <code xmlns="">030</code> + <name xmlns="">xml-eXtensible Markup Language</name> + </Name> + <Version>0.0</Version> + <Primaerdokument> + <Dateiname>%s</Dateiname> + </Primaerdokument> + </Format> + <Format> + <Name listURI="urn:xoev-de:xdomea:codeliste:dateiformat" listVersionID="1.0" xsi:type="DateiformatCodeType"> + <code xmlns="">018</code> + <name xmlns="">pdf-Portable Document Format</name> + </Name> + <Version>0.0</Version> + <Primaerdokument> + <Dateiname>%s</Dateiname> + </Primaerdokument> + </Format> + </Version> + </Dokument> + </Hauptobjekt> + <ExternerGeschaeftsgang> + <Identifikation> + <ID>78fd7cf4-e9b2-4df1-9dc3-3b192a9d61d3</ID> + </Identifikation> + <Beteiligungsschritt> + <Nummer>1</Nummer> + <Status listURI="urn:xoev-de:xdomea:codeliste:beteiligungsstatus" listVersionID="1.0"> + <code xmlns="">001</code> + <name xmlns="">Der Schritt liegt in der Zukunft.</name> + </Status> + <Verfuegung> + <Ersteller> + <Behoerdenkennung> + <Kennung listURI="" listVersionID=""> + <code xmlns="">010200200000</code> + </Kennung> + <Praefix listURI="" listVersionID=""> + <code xmlns="">gad</code> + </Praefix> + </Behoerdenkennung> + </Ersteller> + <Adressat> + <Behoerdenkennung> + <Kennung listURI="" listVersionID=""> + <code xmlns="">dev-environment@ozg-cloud.de</code> + </Kennung> + <Praefix listURI="" listVersionID=""> + <code xmlns="">gae</code> + </Praefix> + </Behoerdenkennung> + </Adressat> + <Erstellungsdatum>2024-04-22</Erstellungsdatum> + <Erstellungsuhrzeit>16:14:18</Erstellungsuhrzeit> + </Verfuegung> + </Beteiligungsschritt> + </ExternerGeschaeftsgang> +</Geschaeftsgang.Geschaeftsgang.0201> diff --git a/xta-adapter/src/test/resources/xdomea/dfoerdermittel_without_anlage.zip b/xta-adapter/src/test/resources/xdomea/dfoerdermittel_without_anlage.zip new file mode 100644 index 0000000000000000000000000000000000000000..a05e0656982591208af644af4478ad6c6fe58f10 Binary files /dev/null and b/xta-adapter/src/test/resources/xdomea/dfoerdermittel_without_anlage.zip differ diff --git a/xta-adapter/src/test/resources/xdomea/mantelantrag_Geschaeftsgang.Geschaeftsgang.0201.xml b/xta-adapter/src/test/resources/xdomea/mantelantrag_Geschaeftsgang.Geschaeftsgang.0201.xml new file mode 100644 index 0000000000000000000000000000000000000000..2897dbe4fd05a17463edbe13d37824ae64d99b59 --- /dev/null +++ b/xta-adapter/src/test/resources/xdomea/mantelantrag_Geschaeftsgang.Geschaeftsgang.0201.xml @@ -0,0 +1,89 @@ +<?xml version="1.0"?> +<xdomea:Geschaeftsgang.Geschaeftsgang.0201 xmlns:xdomea="http://www.xdomea.de/V2.0.1"> + <xdomea:Kopf> + <xdomea:ProzessID>9f1b47d4-d6bf-4ec4-b0ff-1e30bee42ef2</xdomea:ProzessID> + <xdomea:Nachrichtentyp codeName="Geschaeftsgang.Geschaeftsgang.0201" codelistAgencyName="AG XDOMEA des KoopA ADV" codelistVersionIdentifier="2.0.0" languageCode="de" codelistName="Nachrichtentyp">0201</xdomea:Nachrichtentyp> + <xdomea:Erstellungszeitpunkt>2024-04-04T10:24:07.468+02:00</xdomea:Erstellungszeitpunkt> + <xdomea:Absender> + <xdomea:Behoerdenkennung> + <xdomea:Kennung codeName="WebMethod_Online-Dienste">WebMethod_Online-Dienste</xdomea:Kennung> + <xdomea:Praefix codeName="afmsh:">afmsh:</xdomea:Praefix> + </xdomea:Behoerdenkennung> + <xdomea:Institution> + <xdomea:Name>Schleswig-Holstein</xdomea:Name> + <xdomea:Kurzbezeichnung>Schleswig-Holstein</xdomea:Kurzbezeichnung> + </xdomea:Institution> + </xdomea:Absender> + <xdomea:Empfaenger> + <xdomea:Behoerdenkennung> + <xdomea:Kennung codeName="ozg-cloud-dev001">ozg-cloud-dev001</xdomea:Kennung> + <xdomea:Praefix codeName="afmsh:">afmsh:</xdomea:Praefix> + </xdomea:Behoerdenkennung> + </xdomea:Empfaenger> + <xdomea:SendendesSystem> + <xdomea:InstanzID>AFMSH.MSR</xdomea:InstanzID> + <xdomea:Produktname>MSR</xdomea:Produktname> + <xdomea:Version>10.5</xdomea:Version> + </xdomea:SendendesSystem> + <xdomea:EmpfangsbestaetigungAnInitiator>false</xdomea:EmpfangsbestaetigungAnInitiator> + <xdomea:EmpfangsbestaetigungAnVorgaenger>false</xdomea:EmpfangsbestaetigungAnVorgaenger> + </xdomea:Kopf> + <xdomea:Hauptobjekt> + <xdomea:Dokument> + <xdomea:Identifikation> + <xdomea:ID>9bae73b1-2ef3-480b-8acc-8bcd9979a788</xdomea:ID> + </xdomea:Identifikation> + <xdomea:AllgemeineMetadaten> + <xdomea:Betreff>Antrag auf Leistungen der Eingliederungshilfe und/oder Sozialhilfe</xdomea:Betreff> + <xdomea:Kennzeichen>20240404370530710707</xdomea:Kennzeichen> + </xdomea:AllgemeineMetadaten> + <xdomea:Posteingangsdatum>2024-04-04</xdomea:Posteingangsdatum> + <xdomea:Typ>maa_mantelantrag/maa_mantelantrag_pvog</xdomea:Typ> + <xdomea:Version> + <xdomea:Nummer>0.0</xdomea:Nummer> + <xdomea:Format> + <xdomea:Name codeName="xml - eXtensible Markup Language" codelistAgencyName="AG XDOMEA des KoopA ADV" codelistVersionIdentifier="2.0.0" languageCode="de" codelistName="Dateiformat">030</xdomea:Name> + <xdomea:Version>0.0</xdomea:Version> + <xdomea:Primaerdokument> + <xdomea:Dateiname>%s</xdomea:Dateiname> + </xdomea:Primaerdokument> + </xdomea:Format> + </xdomea:Version> + <xdomea:Version> + <xdomea:Nummer>0.0</xdomea:Nummer> + <xdomea:Format> + <xdomea:Name codeName="pdf - Portable Document Format" codelistAgencyName="AG XDOMEA des KoopA ADV" codelistVersionIdentifier="2.0.0" languageCode="de" codelistName="Dateiformat">018</xdomea:Name> + <xdomea:Version>0.0</xdomea:Version> + <xdomea:Primaerdokument> + <xdomea:Dateiname>%s</xdomea:Dateiname> + </xdomea:Primaerdokument> + </xdomea:Format> + </xdomea:Version> + </xdomea:Dokument> + </xdomea:Hauptobjekt> + <xdomea:ExternerGeschaeftsgang> + <xdomea:Identifikation> + <xdomea:ID>8ae49342-8135-4f11-9930-5c4cc55b7ec2</xdomea:ID> + </xdomea:Identifikation> + <xdomea:Beteiligungsschritt> + <xdomea:Nummer>1</xdomea:Nummer> + <xdomea:Status codeName="zukuenftig" codelistAgencyName="AG XDOMEA des KoopA ADV" codelistVersionIdentifier="2.0.0" languageCode="de" codelistName="Beteiligungsstatus">001</xdomea:Status> + <xdomea:Verfuegung> + <xdomea:Ersteller> + <xdomea:Behoerdenkennung> + <xdomea:Kennung codeName="WebMethod_Online-Dienste">WebMethod_Online-Dienste</xdomea:Kennung> + <xdomea:Praefix codeName="afmsh:">afmsh:</xdomea:Praefix> + </xdomea:Behoerdenkennung> + </xdomea:Ersteller> + <xdomea:Adressat> + <xdomea:Behoerdenkennung> + <xdomea:Kennung codeName="ozg-cloud-dev001">ozg-cloud-dev001</xdomea:Kennung> + <xdomea:Praefix codeName="afmsh:">afmsh:</xdomea:Praefix> + </xdomea:Behoerdenkennung> + </xdomea:Adressat> + <xdomea:Erstellungsdatum>2024-04-04</xdomea:Erstellungsdatum> + <xdomea:Erstellungsuhrzeit>10:24:06</xdomea:Erstellungsuhrzeit> + </xdomea:Verfuegung> + </xdomea:Beteiligungsschritt> + </xdomea:ExternerGeschaeftsgang> +</xdomea:Geschaeftsgang.Geschaeftsgang.0201>