diff --git a/common/src/test/java/de/ozgcloud/eingang/common/formdata/FormDataControlTestFactory.java b/common/src/test/java/de/ozgcloud/eingang/common/formdata/FormDataControlTestFactory.java index 4a422c93fb3932064da4ed7d27a52535c5c176f4..13ff8dca255ca89dc1c93c0883541377d231bf40 100644 --- a/common/src/test/java/de/ozgcloud/eingang/common/formdata/FormDataControlTestFactory.java +++ b/common/src/test/java/de/ozgcloud/eingang/common/formdata/FormDataControlTestFactory.java @@ -30,7 +30,7 @@ import de.ozgcloud.eingang.common.formdata.FormData.Representations; public class FormDataControlTestFactory { - public static String PRIMARY_FORM_DATA_REPRESENTATION = "Antrag.xml"; + public static final String PRIMARY_FORM_DATA_REPRESENTATION = "Antrag.xml"; public static FormDataControl create() { return createBuilder().build(); diff --git a/common/src/test/java/de/ozgcloud/eingang/common/formdata/FormDataTestFactory.java b/common/src/test/java/de/ozgcloud/eingang/common/formdata/FormDataTestFactory.java index b950493b78fc2cfdd3b2ce6e5922768e45ad5d54..1c5ceaddf1b27323ff33316cb7328533eb904a96 100644 --- a/common/src/test/java/de/ozgcloud/eingang/common/formdata/FormDataTestFactory.java +++ b/common/src/test/java/de/ozgcloud/eingang/common/formdata/FormDataTestFactory.java @@ -29,6 +29,11 @@ import java.util.HashMap; import java.util.List; import java.util.Map; +import de.ozgcloud.eingang.common.formdata.FormData.FormDataControl; +import lombok.AccessLevel; +import lombok.NoArgsConstructor; + +@NoArgsConstructor(access = AccessLevel.PRIVATE) public class FormDataTestFactory { public static final String SIMPLE_VALUE_KEY = "kontaktsystemtypid"; @@ -53,6 +58,18 @@ public class FormDataTestFactory { public static final String VORGANG_ID = "vorgangId"; + public static final List<IncomingFileGroup> ATTACHMENTS = List.of(IncomingFileGroupTestFactory.create(), + IncomingFileGroupTestFactory.createBuilder().name(ATTACHMENT_GROUP_2).build()); + public static final List<IncomingFile> REPRESENTATIONS = List.of(IncomingFileTestFactory.create()); + + public static final FormDataControl FORM_DATA_CONTROL = FormDataControlTestFactory.create(); + + public static final Map<String, Object> FORM_DATA = Map.of( + SIMPLE_VALUE_KEY, SIMPLE_VALUE, + SUBFORM_KEY, SUBFORM_VALUE, + NESTED_LIST_WITH_STRINGS_KEY, NESTED_LIST_WITH_STRINGS, + NESTED_LIST_WITH_OBJECTS_KEY, NESTED_LIST_WITH_OBJECTS); + public static FormData create() { return createBuilder().build(); } @@ -62,20 +79,15 @@ public class FormDataTestFactory { .header(FormHeaderTestFactory.create()) .antragsteller(AntragstellerTestFactory.create()) .zustaendigeStelle(ZustaendigeStelleTestFactory.create()) - .control(FormDataControlTestFactory.create()) - .formData(Map.of( - SIMPLE_VALUE_KEY, SIMPLE_VALUE, - SUBFORM_KEY, SUBFORM_VALUE, - NESTED_LIST_WITH_STRINGS_KEY, NESTED_LIST_WITH_STRINGS, - NESTED_LIST_WITH_OBJECTS_KEY, NESTED_LIST_WITH_OBJECTS)) + .control(FORM_DATA_CONTROL) + .formData(FORM_DATA) // TODO nach entfernen des zweiten Attachments den Wert auf 1 setzen .numberOfAttachments(2) // TODO zweites Attachment aus der TestFactory entfernen und die entsprechenden // Tests anpassen - .attachments(List.of(IncomingFileGroupTestFactory.create(), - IncomingFileGroupTestFactory.createBuilder().name(ATTACHMENT_GROUP_2).build())) + .attachments(ATTACHMENTS) .numberOfRepresentations(1) - .representations(List.of(IncomingFileTestFactory.create())); + .representations(REPRESENTATIONS); } @SafeVarargs diff --git a/fim-adapter/src/main/java/de/ozgcloud/eingang/fim/AntragstellerMapper.java b/fim-adapter/src/main/java/de/ozgcloud/eingang/fim/AntragstellerMapper.java new file mode 100644 index 0000000000000000000000000000000000000000..0c65466d79e1fdb5f0f5e5472fbd2bed4b013536 --- /dev/null +++ b/fim-adapter/src/main/java/de/ozgcloud/eingang/fim/AntragstellerMapper.java @@ -0,0 +1,56 @@ +package de.ozgcloud.eingang.fim; + +import java.util.Map; +import java.util.Optional; + +import org.apache.commons.collections.MapUtils; +import org.springframework.stereotype.Component; + +import de.ozgcloud.eingang.common.formdata.Antragsteller; +import de.ozgcloud.eingang.common.formdata.FormData; + +@Component +class AntragstellerMapper implements FimEngineBasedMapper { + + static final String ANTRAGSTELLER_KEY = "G17002112"; + + static final String ANSCHRIFT_KEY = "G60000086"; + + static final String VORNAME_KEY = "F60000228"; + static final String NACHNAME_KEY = "F60000227"; + static final String EMAIL_KEY = "F60000242"; + static final String STRASSE_KEY = "F60000243"; + static final String HAUSNUMMER_KEY = "F60000244"; + static final String PLZ_KEY = "F60000246"; + static final String ORT_KEY = "F60000247"; + + @Override + public FormData parseFormData(FormData formData) { + return Optional.ofNullable(getAntragsteller(formData.getFormData())) + .filter(MapUtils::isNotEmpty) + .map(this::mapAntragsteller) + .map(antragsteller -> formData.toBuilder().antragsteller(antragsteller).build()).orElse(formData); + } + + Map<String, Object> getAntragsteller(Map<String, Object> formData) { + return FimDataUtil.getValueMapByKey(formData, ANTRAGSTELLER_KEY); + } + + Antragsteller mapAntragsteller(Map<String, Object> antragsteller) { + var anschrift = getAnschrift(antragsteller); + + return Antragsteller.builder() + .vorname(FimDataUtil.getValueByKey(antragsteller, VORNAME_KEY).orElse(null)) + .nachname(FimDataUtil.getValueByKey(antragsteller, NACHNAME_KEY).orElse(null)) + .email(FimDataUtil.getValueByKey(antragsteller, EMAIL_KEY).orElse(null)) + .strasse(FimDataUtil.getValueByKey(anschrift, STRASSE_KEY).orElse(null)) + .hausnummer(FimDataUtil.getValueByKey(anschrift, HAUSNUMMER_KEY).orElse(null)) + .plz(FimDataUtil.getValueByKey(anschrift, PLZ_KEY).orElse(null)) + .ort(FimDataUtil.getValueByKey(anschrift, ORT_KEY).orElse(null)) + .build(); + } + + private Map<String, Object> getAnschrift(Map<String, Object> antragsteller) { + return FimDataUtil.getValueMapByKey(antragsteller, ANSCHRIFT_KEY); + } +} \ No newline at end of file diff --git a/fim-adapter/src/main/java/de/ozgcloud/eingang/fim/FimBasedAdapter.java b/fim-adapter/src/main/java/de/ozgcloud/eingang/fim/FimBasedAdapter.java index 40c89aa15f25da54579d2cf79f75cb636fdb359b..296f4efff44fbbbe24eb898d644164db9c029a42 100644 --- a/fim-adapter/src/main/java/de/ozgcloud/eingang/fim/FimBasedAdapter.java +++ b/fim-adapter/src/main/java/de/ozgcloud/eingang/fim/FimBasedAdapter.java @@ -23,97 +23,63 @@ */ package de.ozgcloud.eingang.fim; -import java.io.IOException; import java.util.Collections; import java.util.List; -import java.util.Optional; +import java.util.Map; -import javax.xml.parsers.DocumentBuilder; -import javax.xml.parsers.DocumentBuilderFactory; -import javax.xml.parsers.ParserConfigurationException; - -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import org.w3c.dom.Document; -import org.xml.sax.SAXException; import de.ozgcloud.eingang.common.formdata.FormData; -import de.ozgcloud.eingang.common.formdata.FormData.FormDataControl; -import de.ozgcloud.eingang.common.formdata.FormData.Representations; import de.ozgcloud.eingang.common.formdata.IncomingFile; +import de.ozgcloud.eingang.fim.common.xml.DocumentHelper; import de.ozgcloud.eingang.semantik.enginebased.EngineBasedSemantikAdapter; -import lombok.NonNull; +import lombok.RequiredArgsConstructor; import lombok.extern.log4j.Log4j2; @Log4j2 +@RequiredArgsConstructor @Component public class FimBasedAdapter implements EngineBasedSemantikAdapter { static final String FIM_FORM_ENGINE_NAME = "FIM"; - static final String DEFAULT_FORMDATA_REPRESENTATION_NAME = "Antrag.xml"; - - @Autowired - private FimService fimService; - - @Autowired(required = false) - private List<FimEngineBasedMapper> mappers = Collections.emptyList(); + private final List<FimEngineBasedMapper> mappers; + private final FimService service; @Override - public boolean isResponsible(final FormData formData) { - final String formEngineName = formData.getHeader().getFormEngineName(); - return FIM_FORM_ENGINE_NAME.equals(formEngineName); + public boolean isResponsible(FormData formData) { + return FIM_FORM_ENGINE_NAME.equals(formData.getHeader().getFormEngineName()); } @Override - public FormData parseFormData(final FormData initialFormData) { - var mapped = useMappers(initialFormData); - LOG.info("FIM Mapper running to map formData"); - - return findFile(initialFormData, getEntryPoint(initialFormData.getControl())) - .map(primaryRepresentation -> doParsing(mapped, primaryRepresentation)) - .orElseGet(() -> { - LOG.error("Entry point file not found for fim data mapping"); - return mapped; - }); - } - - private FormData useMappers(FormData inFormData) { - var processedFormData = inFormData; + public FormData parseFormData(FormData formData) { + var processedFormData = addFormDataDataMap(formData); for (var mapper : mappers) { processedFormData = mapper.parseFormData(processedFormData); } - return processedFormData; } - private Optional<IncomingFile> findFile(final FormData formData, final String name) { - return formData.getRepresentations().stream() - .filter(file -> file.getName().endsWith(name)) - .findFirst(); + FormData addFormDataDataMap(FormData formData) { + return formData.toBuilder().formData(parseRequestData(formData)).build(); } - private FormData doParsing(@NonNull FormData formData, @NonNull IncomingFile formDataPrimaryRepresentation) { - try { - return fimService.transformDocument(loadDocument(formDataPrimaryRepresentation), formData); - } catch (ParserConfigurationException | SAXException | IOException | FimException e) { - LOG.error("Can't transform document into fim formdata.", e); - return formData; - } + Map<String, Object> parseRequestData(FormData formData) { + return service.findPrimaryRepresentation(formData).map(this::doParse).orElseGet(Collections::emptyMap); } - String getEntryPoint(FormDataControl formDataControl) { - return formDataControl.getRepresentations().map(Representations::getPrimaryFormDataRepresentation) - .orElseGet(() -> { - LOG.error("No entry point found in metadata file for fim data mapping. Trying default."); - return DEFAULT_FORMDATA_REPRESENTATION_NAME; - }); + Map<String, Object> doParse(IncomingFile file) { + try { + return processData(DocumentHelper.parse(file.getContentStream())); + } catch (Exception e) { + LOG.warn("Error on parsing Document.", e); + return Collections.emptyMap(); + } } - private Document loadDocument(final IncomingFile incomingFile) throws ParserConfigurationException, IOException, SAXException { - final DocumentBuilder builder = DocumentBuilderFactory.newInstance().newDocumentBuilder(); - return builder.parse(incomingFile.getContentStream()); + Map<String, Object> processData(Document content) { + return FimDocumentHelper.createProcessor(content, service.getScheme(content)).process(); } - -} +} \ No newline at end of file diff --git a/fim-adapter/src/main/java/de/ozgcloud/eingang/fim/FimDataMapper.java b/fim-adapter/src/main/java/de/ozgcloud/eingang/fim/FimDataMapper.java deleted file mode 100644 index 356de8554712b4f7cf7bda8ad1de0cafce54bea3..0000000000000000000000000000000000000000 --- a/fim-adapter/src/main/java/de/ozgcloud/eingang/fim/FimDataMapper.java +++ /dev/null @@ -1,81 +0,0 @@ -/* - * Copyright (C) 2024 Das Land Schleswig-Holstein vertreten durch den - * Ministerpräsidenten des Landes Schleswig-Holstein - * Staatskanzlei - * Abteilung Digitalisierung und zentrales IT-Management der Landesregierung - * - * Lizenziert unter der EUPL, Version 1.2 oder - sobald - * diese von der Europäischen Kommission genehmigt wurden - - * Folgeversionen der EUPL ("Lizenz"); - * Sie dürfen dieses Werk ausschließlich gemäß - * dieser Lizenz nutzen. - * Eine Kopie der Lizenz finden Sie hier: - * - * https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 - * - * Sofern nicht durch anwendbare Rechtsvorschriften - * gefordert oder in schriftlicher Form vereinbart, wird - * die unter der Lizenz verbreitete Software "so wie sie - * ist", OHNE JEGLICHE GEWÄHRLEISTUNG ODER BEDINGUNGEN - - * ausdrücklich oder stillschweigend - verbreitet. - * Die sprachspezifischen Genehmigungen und Beschränkungen - * unter der Lizenz sind dem Lizenztext zu entnehmen. - */ -package de.ozgcloud.eingang.fim; - -import java.util.LinkedHashMap; -import java.util.Map; -import java.util.Optional; - -import org.apache.commons.lang3.function.TriFunction; -import org.springframework.stereotype.Service; -import org.w3c.dom.Document; -import org.w3c.dom.Element; -import org.w3c.dom.Node; -import org.w3c.dom.NodeList; -import org.w3c.dom.Text; - -import de.ozgcloud.eingang.common.formdata.FormData; -import lombok.extern.log4j.Log4j2; - -@Service -@Log4j2 -class FimDataMapper implements TriFunction<Document, FimScheme, FormData, FormData.FormDataBuilder> { - - private static final String LABEL_KEY = "label"; - private static final String VALUE_KEY = "value"; - - @Override - public FormData.FormDataBuilder apply(final Document document, final FimScheme fimScheme, final FormData initialFormData) { - final FormData.FormDataBuilder formDataBuilder = initialFormData.toBuilder(); - Map<String, Object> data = new LinkedHashMap<>(); - process(document.getDocumentElement(), fimScheme, data, 0); - formDataBuilder.formData(data); - return formDataBuilder; - } - - private void process(final Element element, final FimScheme fimScheme, final Map<String, Object> data, final int level) { - final NodeList childNodes = element.getChildNodes(); - - LOG.debug(">".repeat(level) + " " + element.getNodeName()); - - for (int i = 0; i < childNodes.getLength(); i++) { - final Node child = childNodes.item(i); - if (!(child instanceof Element)) { - continue; - } - if (child.getChildNodes().getLength() == 1 && child.getChildNodes().item(0) instanceof Text textNode) { - insertValueIntoFormData(data, fimScheme.getFieldName(child.getNodeName()), child.getNodeName(), textNode.getTextContent()); - } else { - final Map<String, Object> childMap = new LinkedHashMap<>(); - insertValueIntoFormData(data, fimScheme.getFieldName(child.getNodeName()), child.getNodeName(), childMap); - process((Element) child, fimScheme, childMap, level + 1); - } - } - } - - private void insertValueIntoFormData(final Map<String, Object> data, final Optional<String> fieldName, final String nodeName, final Object obj) { - final Map<String, Object> labelMap = Map.of(LABEL_KEY, fieldName.orElse(nodeName), VALUE_KEY, obj); - data.put(nodeName, labelMap); - } -} diff --git a/fim-adapter/src/main/java/de/ozgcloud/eingang/fim/FimDataUtil.java b/fim-adapter/src/main/java/de/ozgcloud/eingang/fim/FimDataUtil.java new file mode 100644 index 0000000000000000000000000000000000000000..6d527356735d785b8f113da8d22473e8d200611c --- /dev/null +++ b/fim-adapter/src/main/java/de/ozgcloud/eingang/fim/FimDataUtil.java @@ -0,0 +1,54 @@ +package de.ozgcloud.eingang.fim; + +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; + +import org.apache.commons.collections4.MapUtils; + +import lombok.AccessLevel; +import lombok.NoArgsConstructor; + +@NoArgsConstructor(access = AccessLevel.PRIVATE) +class FimDataUtil { + + static final String VALUE_KEY = "value"; + + public static Optional<String> getValue(Map<String, Object> data, List<String> pathKeys, String key) { + var current = FimDataUtil.getSubmap(data, pathKeys); + if (Objects.isNull(current)) { + return Optional.empty(); + } + return FimDataUtil.getValueByKey(current, key); + } + + private static Map<String, Object> getSubmap(Map<String, Object> data, List<String> pathKeys) { + var current = data; + for (var pathKey : pathKeys) { + current = FimDataUtil.getValueMapByKey(current, pathKey); + } + return current; + } + + static Map<String, Object> getValueMapByKey(Map<String, Object> obj, String key) { + return Optional.ofNullable(MapUtils.getMap(obj, key)) + .map(FimDataUtil::castToMap) + .map(FimDataUtil::getValueAsMap) + .orElse(null); + } + + public static Optional<String> getValueByKey(Map<String, Object> data, String key) { + var map = FimDataUtil.castToMap(MapUtils.getMap(data, key)); + return Optional.ofNullable(MapUtils.getString(map, VALUE_KEY)); + } + + @SuppressWarnings("unchecked") + private static Map<String, Object> castToMap(Map<?, ?> obj) { + return (Map<String, Object>) obj; + } + + private static Map<String, Object> getValueAsMap(Map<String, Object> map) { + return FimDataUtil.castToMap(MapUtils.getMap(map, VALUE_KEY)); + } +} \ No newline at end of file diff --git a/fim-adapter/src/main/java/de/ozgcloud/eingang/fim/FimDocumentReader.java b/fim-adapter/src/main/java/de/ozgcloud/eingang/fim/FimDocumentReader.java new file mode 100644 index 0000000000000000000000000000000000000000..de7e3961ccb4ae9b99eedf79c8c25beccc4d4abb --- /dev/null +++ b/fim-adapter/src/main/java/de/ozgcloud/eingang/fim/FimDocumentReader.java @@ -0,0 +1,71 @@ +package de.ozgcloud.eingang.fim; + +import java.util.Collections; +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.Optional; + +import org.springframework.stereotype.Component; +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.Node; + +import de.ozgcloud.eingang.fim.common.xml.DocumentHelper; +import lombok.AccessLevel; +import lombok.NoArgsConstructor; +import lombok.RequiredArgsConstructor; +import lombok.extern.log4j.Log4j2; + +@NoArgsConstructor(access = AccessLevel.PRIVATE) +@Component +class FimDocumentHelper { + + public static FimDocumentProcessor createProcessor(Document doc, FimScheme fimScheme) { + return new FimDocumentProcessor(doc, fimScheme); + } + + @Log4j2 + @RequiredArgsConstructor(access = AccessLevel.PRIVATE) + static class FimDocumentProcessor { + + private static final String LABEL_KEY = "label"; + private static final String VALUE_KEY = "value"; + + private final Document document; + private final FimScheme scheme; + + public Map<String, Object> process() { + var data = new LinkedHashMap<String, Object>(); + processNode(document.getDocumentElement(), data); + return Collections.unmodifiableMap(data); + } + + void processNode(Node element, Map<String, Object> data) { + LOG.debug(() -> "process node... " + element.getNodeName()); + DocumentHelper.getChildNodes(element.getChildNodes()).forEach(childElement -> processElement(childElement, data)); + } + + void processElement(Element element, Map<String, Object> data) { + if (DocumentHelper.isTextNode(element)) { + addToMap(element, data, element.getTextContent()); + } else { + var childMap = new LinkedHashMap<String, Object>(); + addToMap(element, data, childMap); + processNode(element, childMap); + } + } + + private void addToMap(Element element, Map<String, Object> data, Object value) { + var fieldName = DocumentHelper.getFieldNameWithoutNamespace(element.getNodeName()); + data.put(fieldName, buildFieldMap(getFieldName(element).orElse(fieldName), value)); + } + + private Optional<String> getFieldName(Element element) { + return scheme.getFieldName(element.getNodeName()); + } + + private Map<String, Object> buildFieldMap(String fieldName, Object obj) { + return Map.of(LABEL_KEY, fieldName, VALUE_KEY, obj); + } + } +} \ No newline at end of file diff --git a/fim-adapter/src/main/java/de/ozgcloud/eingang/fim/FimEngineBasedMapper.java b/fim-adapter/src/main/java/de/ozgcloud/eingang/fim/FimEngineBasedMapper.java index 2f34d15f42093ac02f0a3f09a6e903d44ed411a3..95cf88f883ca4cc3b8cdaab223abe62a6db1d58a 100644 --- a/fim-adapter/src/main/java/de/ozgcloud/eingang/fim/FimEngineBasedMapper.java +++ b/fim-adapter/src/main/java/de/ozgcloud/eingang/fim/FimEngineBasedMapper.java @@ -25,6 +25,5 @@ package de.ozgcloud.eingang.fim; import de.ozgcloud.eingang.semantik.enginebased.EngineBasedMapper; -public interface FimEngineBasedMapper extends EngineBasedMapper { - -} +interface FimEngineBasedMapper extends EngineBasedMapper { +} \ No newline at end of file diff --git a/fim-adapter/src/main/java/de/ozgcloud/eingang/fim/FimException.java b/fim-adapter/src/main/java/de/ozgcloud/eingang/fim/FimException.java deleted file mode 100644 index 11e916d6d3e4d1c473226d45140292ce97c3bf0c..0000000000000000000000000000000000000000 --- a/fim-adapter/src/main/java/de/ozgcloud/eingang/fim/FimException.java +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright (C) 2024 Das Land Schleswig-Holstein vertreten durch den - * Ministerpräsidenten des Landes Schleswig-Holstein - * Staatskanzlei - * Abteilung Digitalisierung und zentrales IT-Management der Landesregierung - * - * Lizenziert unter der EUPL, Version 1.2 oder - sobald - * diese von der Europäischen Kommission genehmigt wurden - - * Folgeversionen der EUPL ("Lizenz"); - * Sie dürfen dieses Werk ausschließlich gemäß - * dieser Lizenz nutzen. - * Eine Kopie der Lizenz finden Sie hier: - * - * https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 - * - * Sofern nicht durch anwendbare Rechtsvorschriften - * gefordert oder in schriftlicher Form vereinbart, wird - * die unter der Lizenz verbreitete Software "so wie sie - * ist", OHNE JEGLICHE GEWÄHRLEISTUNG ODER BEDINGUNGEN - - * ausdrücklich oder stillschweigend - verbreitet. - * Die sprachspezifischen Genehmigungen und Beschränkungen - * unter der Lizenz sind dem Lizenztext zu entnehmen. - */ -package de.ozgcloud.eingang.fim; - -import de.ozgcloud.eingang.common.errorhandling.TechnicalException; - -public class FimException extends TechnicalException { - public FimException(final String ex) { - super(ex); - } -} diff --git a/fim-adapter/src/main/java/de/ozgcloud/eingang/fim/FimProperties.java b/fim-adapter/src/main/java/de/ozgcloud/eingang/fim/FimProperties.java index b86a4c8c498572c4de9fad70afd34a68571c15db..331f762134ab26efdacec306e1a031a894912297 100644 --- a/fim-adapter/src/main/java/de/ozgcloud/eingang/fim/FimProperties.java +++ b/fim-adapter/src/main/java/de/ozgcloud/eingang/fim/FimProperties.java @@ -23,26 +23,27 @@ */ package de.ozgcloud.eingang.fim; +import java.util.ArrayList; +import java.util.List; + import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.context.annotation.Configuration; -import lombok.Getter; -import org.springframework.validation.annotation.Validated; -import java.util.ArrayList; -import java.util.List; +import lombok.Getter; -@Validated +@Getter @Configuration @ConfigurationProperties(prefix = FimProperties.PROPERTIES_PREFIX) -@Getter public class FimProperties { - static final String PROPERTIES_PREFIX = "fim"; + static final String PROPERTIES_PREFIX = "ozgcloud.eingang.fim"; - /** - * List of paths to fim scheme files which should be processed by the fim-adapter. - * - * Only fim data that is in the namespace and versions of these files will be mapped by the fim-adapter. - * All other fim data will be left untouched by the mapper. - */ - private final List<String> schemeLocations = new ArrayList<>(); + /** + * List of paths to fim scheme files which should be processed by the + * fim-adapter. + * + * Only fim data that is in the namespace and versions of these files will be + * mapped by the fim-adapter. All other fim data will be left untouched by the + * mapper. + */ + private final List<String> schemeLocations = new ArrayList<>(); } diff --git a/fim-adapter/src/main/java/de/ozgcloud/eingang/fim/FimScheme.java b/fim-adapter/src/main/java/de/ozgcloud/eingang/fim/FimScheme.java index c24300aef807df868642067b6182b1678307e170..09ebd93c03d16cb7268f4bbdce32dae53a98ee82 100644 --- a/fim-adapter/src/main/java/de/ozgcloud/eingang/fim/FimScheme.java +++ b/fim-adapter/src/main/java/de/ozgcloud/eingang/fim/FimScheme.java @@ -23,43 +23,48 @@ */ package de.ozgcloud.eingang.fim; -import lombok.Getter; +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.Optional; + import org.w3c.dom.Document; import org.w3c.dom.Element; - import org.w3c.dom.NodeList; -import java.util.LinkedHashMap; -import java.util.Map; -import java.util.Optional; +import de.ozgcloud.eingang.fim.common.xml.DocumentHelper; +import lombok.Getter; class FimScheme { - private final Document doc; - @Getter - private final FimSchemeIdentifier identifier; + private final Document doc; + @Getter + private final FimSchemeIdentifier identifier; + + @Getter + private final FimSchemeAdapter schemeAdapter; + private final Map<String, Element> fieldIndex = new LinkedHashMap<>(); + + public FimScheme(Document doc, FimSchemeIdentifier identifier, FimSchemeAdapter schemeAdapter) { + this.doc = doc; + this.identifier = identifier; + this.schemeAdapter = schemeAdapter; + + buildFieldIndex(); + } - @Getter - private final FimSchemeAdapter schemeAdapter; - private final Map<String, Element> fieldIndex = new LinkedHashMap<>(); + private void buildFieldIndex() { + DocumentHelper.getChildNodes(getElements()).forEach(group -> fieldIndex.put(getName(group), group)); + } - FimScheme(final Document doc, final FimSchemeIdentifier identifier, final FimSchemeAdapter schemeAdapter) { - this.doc = doc; - this.identifier = identifier; - this.schemeAdapter = schemeAdapter; + private NodeList getElements() { + return doc.getElementsByTagName("xs:element"); + } - buildFieldIndex(); - } - private void buildFieldIndex() { - final NodeList groupList = doc.getElementsByTagName("xs:element"); - for (int i = 0; i < groupList.getLength();i++) { - final Element group = (Element) groupList.item(i); - final String groupName = group.getAttribute("name"); - fieldIndex.put(groupName, group); - } - } + private String getName(Element element) { + return element.getAttribute("name"); + } - Optional<String> getFieldName(final String fieldName) { - return schemeAdapter.getFieldName(fieldIndex, fieldName); - } + Optional<String> getFieldName(String fieldName) { + return schemeAdapter.getFieldName(fieldIndex, fieldName); + } } diff --git a/fim-adapter/src/main/java/de/ozgcloud/eingang/fim/FimSchemeAdapter.java b/fim-adapter/src/main/java/de/ozgcloud/eingang/fim/FimSchemeAdapter.java index 1afaa1d1d097479edc336f2db195494a94455a10..593d4b614e1602523780d90cd46a8295aed8a296 100644 --- a/fim-adapter/src/main/java/de/ozgcloud/eingang/fim/FimSchemeAdapter.java +++ b/fim-adapter/src/main/java/de/ozgcloud/eingang/fim/FimSchemeAdapter.java @@ -27,36 +27,26 @@ import java.util.Map; import java.util.Optional; import org.w3c.dom.Element; -import org.w3c.dom.NodeList; +import de.ozgcloud.eingang.fim.common.xml.DocumentHelper; import lombok.extern.log4j.Log4j2; @Log4j2 -public abstract class FimSchemeAdapter { +abstract class FimSchemeAdapter { - public abstract FimSchemeIdentifier forIdentifier(); + public abstract FimSchemeIdentifier getIdentifier(); - public Optional<String> getFieldName(final Map<String, Element> fieldIndex, final String fieldName) { - final String[] fieldNameParts = fieldName.split(":"); - final String fieldNameWithoutNamespace = fieldNameParts[fieldNameParts.length - 1]; - if (!fieldIndex.containsKey(fieldNameWithoutNamespace)) { - LOG.error("Cannot find Field: " + fieldName); - return Optional.empty(); - } - final Element nodeNameElement = fieldIndex.get(fieldNameWithoutNamespace); - final Optional<String> nodeNameOpt = getNameForElement(nodeNameElement); - return nodeNameOpt.map(this::cleanNodeName); - } + public Optional<String> getFieldName(Map<String, Element> fieldIndex, String fieldName) { + var fieldNameWithoutNamespace = DocumentHelper.getFieldNameWithoutNamespace(fieldName); - public Optional<String> getNameForElement(final Element element) { - final NodeList nameTags = element.getElementsByTagName("name"); - if (nameTags.getLength() != 1) { + if (!fieldIndex.containsKey(fieldNameWithoutNamespace)) { + LOG.error("Cannot find Field: {}", fieldName); return Optional.empty(); } - return Optional.ofNullable(nameTags.item(0).getTextContent()); + return getNameForElement(fieldIndex.get(fieldNameWithoutNamespace)); } - public String cleanNodeName(final String s) { - return s.trim(); + public Optional<String> getNameForElement(Element element) { + return DocumentHelper.getChildElement(element, "name"); } } diff --git a/fim-adapter/src/main/java/de/ozgcloud/eingang/fim/FimSchemeAdapterCatalogue.java b/fim-adapter/src/main/java/de/ozgcloud/eingang/fim/FimSchemeAdapterCatalogue.java index ad4cf21ce157701c80138d7a6a7f1664dc0090a8..64d1845a9067ae8ef0c9b36df92948c9df387386 100644 --- a/fim-adapter/src/main/java/de/ozgcloud/eingang/fim/FimSchemeAdapterCatalogue.java +++ b/fim-adapter/src/main/java/de/ozgcloud/eingang/fim/FimSchemeAdapterCatalogue.java @@ -24,5 +24,8 @@ package de.ozgcloud.eingang.fim; import java.util.LinkedHashMap; + class FimSchemeAdapterCatalogue extends LinkedHashMap<FimSchemeIdentifier, FimSchemeAdapter> { + + private static final long serialVersionUID = 1L; } diff --git a/fim-adapter/src/main/java/de/ozgcloud/eingang/fim/FimSchemeCatalogue.java b/fim-adapter/src/main/java/de/ozgcloud/eingang/fim/FimSchemeCatalogue.java index 8e0eb74a535d126f6845f5ef1556ca1e0355a21f..3dac7c86f62fdd6f870743cbdcfdb17f935a94b1 100644 --- a/fim-adapter/src/main/java/de/ozgcloud/eingang/fim/FimSchemeCatalogue.java +++ b/fim-adapter/src/main/java/de/ozgcloud/eingang/fim/FimSchemeCatalogue.java @@ -23,7 +23,93 @@ */ package de.ozgcloud.eingang.fim; +import java.io.File; +import java.io.IOException; import java.util.LinkedHashMap; -class FimSchemeCatalogue extends LinkedHashMap<FimSchemeIdentifier, FimScheme> { -} +import javax.xml.parsers.ParserConfigurationException; + +import org.springframework.core.io.ResourceLoader; +import org.w3c.dom.Document; +import org.xml.sax.SAXException; + +import de.ozgcloud.eingang.common.errorhandling.TechnicalException; +import de.ozgcloud.eingang.fim.common.xml.DocumentHelper; +import lombok.extern.log4j.Log4j2; + +@Log4j2 +class FimSchemeCatalogue extends LinkedHashMap<FimSchemeIdentifier, FimScheme> { // NOSONAR + + private static final long serialVersionUID = 1L; + + private final transient FimProperties fimProperties; + private final transient ResourceLoader resourceLoader; + private final transient FimSchemeAdapterCatalogue adapterCatalogue; + + private static final FimSchemeAdapter DEFAULT_FIM_SCHEME_ADAPTER = new FimSchemeAdapter() { + @Override + public FimSchemeIdentifier getIdentifier() { + return null; + } + }; + + public FimSchemeCatalogue(FimProperties fimProperties, ResourceLoader resourceLoader, FimSchemeAdapterCatalogue adapterCatalogue) { + this.fimProperties = fimProperties; + this.resourceLoader = resourceLoader; + this.adapterCatalogue = adapterCatalogue; + + initSchemes(); + } + + private void initSchemes() { + try { + initScheme(); + + initUnknownScheme(); + } catch (ParserConfigurationException | IOException | SAXException e) { + throw new TechnicalException("Error on initialising FimSchemes.", e); + } + } + + private void initScheme() throws ParserConfigurationException, IOException, SAXException { + for (var fimSchemaLocation : fimProperties.getSchemeLocations()) { + put(loadFimScheme(fimSchemaLocation.trim())); + } + } + + private void initUnknownScheme() throws ParserConfigurationException { + put(createScheme(DocumentHelper.getDocumentBuilder().newDocument(), UnknownSchemeAdapter.UNKNOWN_SCHEME_NAME)); + } + + private FimScheme loadFimScheme(String path) throws ParserConfigurationException, IOException, SAXException { + LOG.debug(() -> "Load FIM schema: " + path); + var doc = DocumentHelper.parse(getFile(path)); + return createScheme(doc, getTargetNamespace(doc)); + } + + private void put(FimScheme scheme) { + this.put(scheme.getIdentifier(), scheme); + } + + private File getFile(String path) throws IOException { + return resourceLoader.getResource("classpath:" + path).getFile(); + } + + private String getTargetNamespace(Document doc) { + return doc.getDocumentElement().getAttribute("targetNamespace"); + } + + private FimScheme createScheme(Document doc, String identifierName) { + var identifier = getIdentifierFromString(identifierName); + var adapter = getFimSchemeAdapter(identifier); + return new FimScheme(doc, identifier, adapter); + } + + private FimSchemeIdentifier getIdentifierFromString(String name) { + return FimSchemeIdentifier.fromString(name); + } + + private FimSchemeAdapter getFimSchemeAdapter(FimSchemeIdentifier identifier) { + return adapterCatalogue.getOrDefault(identifier, DEFAULT_FIM_SCHEME_ADAPTER); + } +} \ No newline at end of file diff --git a/fim-adapter/src/main/java/de/ozgcloud/eingang/fim/FimSchemeHelper.java b/fim-adapter/src/main/java/de/ozgcloud/eingang/fim/FimSchemeHelper.java new file mode 100644 index 0000000000000000000000000000000000000000..054589340915925e6aa49ca9da20c88858eb377b --- /dev/null +++ b/fim-adapter/src/main/java/de/ozgcloud/eingang/fim/FimSchemeHelper.java @@ -0,0 +1,46 @@ +package de.ozgcloud.eingang.fim; + +import java.util.List; + +import jakarta.annotation.PostConstruct; + +import org.springframework.core.io.ResourceLoader; +import org.springframework.stereotype.Component; + +import lombok.RequiredArgsConstructor; + +@RequiredArgsConstructor +@Component +class FimSchemeHelper { + + private final FimProperties fimProperties; + private final ResourceLoader resourceLoader; + private final List<FimSchemeAdapter> fimSchemeAdapters; + + private FimSchemeAdapterCatalogue schemeAdapterCatalogue; + private FimSchemeCatalogue schemeCatalogue; + + @PostConstruct + void init() { + initSchemeAdapterCatalogue(); + initSchemeCatalogue(); + } + + private void initSchemeAdapterCatalogue() { + schemeAdapterCatalogue = new FimSchemeAdapterCatalogue(); + + fimSchemeAdapters.forEach(adapter -> schemeAdapterCatalogue.put(adapter.getIdentifier(), adapter)); + } + + private void initSchemeCatalogue() { + schemeCatalogue = new FimSchemeCatalogue(fimProperties, resourceLoader, schemeAdapterCatalogue); + } + + public FimScheme getScheme(String identifier) { + return schemeCatalogue.get(FimSchemeIdentifier.fromString(identifier)); + } + + public FimScheme getDefaultScheme() { + return schemeCatalogue.get(UnknownSchemeAdapter.IDENTIFIER); + } +} \ No newline at end of file diff --git a/fim-adapter/src/main/java/de/ozgcloud/eingang/fim/FimSchemeIdentifier.java b/fim-adapter/src/main/java/de/ozgcloud/eingang/fim/FimSchemeIdentifier.java index d7a2d14aad2880adc015a7f7873221d0a599f557..206e4ac9319533fc19c11c3accf76e99c7fecc1b 100644 --- a/fim-adapter/src/main/java/de/ozgcloud/eingang/fim/FimSchemeIdentifier.java +++ b/fim-adapter/src/main/java/de/ozgcloud/eingang/fim/FimSchemeIdentifier.java @@ -23,18 +23,17 @@ */ package de.ozgcloud.eingang.fim; +import lombok.AccessLevel; import lombok.EqualsAndHashCode; +import lombok.RequiredArgsConstructor; +@RequiredArgsConstructor(access = AccessLevel.PRIVATE) @EqualsAndHashCode -public class FimSchemeIdentifier { +class FimSchemeIdentifier { - private final String schemeId; + private final String schemeId; - FimSchemeIdentifier(String schemeId) { - this.schemeId = schemeId; - } - - public static FimSchemeIdentifier fromString(final String s) { - return new FimSchemeIdentifier(s); - } + public static FimSchemeIdentifier fromString(String schemeId) { + return new FimSchemeIdentifier(schemeId); + } } diff --git a/fim-adapter/src/main/java/de/ozgcloud/eingang/fim/FimService.java b/fim-adapter/src/main/java/de/ozgcloud/eingang/fim/FimService.java index b77187ac905cb6e73b864193a0de7bb5c9e82516..436b4cf677b40d547fc3b37d691a65312ee30b4d 100644 --- a/fim-adapter/src/main/java/de/ozgcloud/eingang/fim/FimService.java +++ b/fim-adapter/src/main/java/de/ozgcloud/eingang/fim/FimService.java @@ -23,105 +23,60 @@ */ package de.ozgcloud.eingang.fim; -import java.io.IOException; -import java.util.ArrayList; -import java.util.List; +import java.util.Objects; +import java.util.Optional; -import javax.xml.parsers.DocumentBuilder; -import javax.xml.parsers.DocumentBuilderFactory; -import javax.xml.parsers.ParserConfigurationException; - -import jakarta.annotation.PostConstruct; - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.core.io.ResourceLoader; +import org.apache.commons.lang3.StringUtils; import org.springframework.stereotype.Service; import org.w3c.dom.Document; -import org.xml.sax.SAXException; import de.ozgcloud.eingang.common.formdata.FormData; -import io.micrometer.common.util.StringUtils; +import de.ozgcloud.eingang.common.formdata.FormData.FormDataControl; +import de.ozgcloud.eingang.common.formdata.FormData.Representations; +import de.ozgcloud.eingang.common.formdata.IncomingFile; +import de.ozgcloud.eingang.fim.common.errorhandling.FimException; +import de.ozgcloud.eingang.fim.common.xml.DocumentHelper; +import lombok.RequiredArgsConstructor; import lombok.extern.log4j.Log4j2; -@Service @Log4j2 +@RequiredArgsConstructor +@Service public class FimService { - public static final String UNKNOWN_SCHEME_NAME = "unknown"; - - @Autowired - private FimProperties fimProperties; - @Autowired - private FimDataMapper fimDataMapper; + static final String DEFAULT_FORMDATA_REPRESENTATION_NAME = "Antrag.xml"; - @Autowired - private ResourceLoader resourceLoader; - - @Autowired - private final List<FimSchemeAdapter> fimSchemeAdapters = new ArrayList<>(); - - private final FimSchemeCatalogue fimSchemeCatalogue = new FimSchemeCatalogue(); - private final FimSchemeAdapterCatalogue fimSchemeAdapterCatalogue = new FimSchemeAdapterCatalogue(); - - private static final FimSchemeAdapter DEFAULT_FIM_SCHEME_ADAPTER = new FimSchemeAdapter() { - @Override - public FimSchemeIdentifier forIdentifier() { - return null; - } - }; + private final FimSchemeHelper schemeHelper; - @PostConstruct - private void postConstruct() throws ParserConfigurationException, IOException, SAXException { - for (final FimSchemeAdapter fimSchemeAdapter : fimSchemeAdapters) { - fimSchemeAdapterCatalogue.put(fimSchemeAdapter.forIdentifier(), fimSchemeAdapter); - } - for (final String fimSchemaLocation : fimProperties.getSchemeLocations()) { - final FimScheme fimScheme = loadFimScheme(fimSchemaLocation.trim()); - fimSchemeCatalogue.put(fimScheme.getIdentifier(), fimScheme); - } - final FimScheme unknownScheme = buildUnknownScheme(); - fimSchemeCatalogue.put(unknownScheme.getIdentifier(), unknownScheme); + public Optional<IncomingFile> findPrimaryRepresentation(FormData formData) { + var representationName = getRepresentationName(formData.getControl()); + return formData.getRepresentations().stream() + .filter(file -> file.getName().endsWith(representationName)) + .findFirst(); } - private FimScheme loadFimScheme(final String path) throws ParserConfigurationException, IOException, SAXException { - LOG.debug("Load FIM schema: " + path); - final DocumentBuilder builder = DocumentBuilderFactory.newInstance().newDocumentBuilder(); - final Document doc = builder.parse(resourceLoader.getResource("classpath:" + path).getFile()); - final String targetNamespace = doc.getDocumentElement().getAttribute("targetNamespace"); - final FimSchemeIdentifier fimSchemeIdentifier = FimSchemeIdentifier.fromString(targetNamespace); - final FimSchemeAdapter fimSchemeAdapter = fimSchemeAdapterCatalogue.getOrDefault(fimSchemeIdentifier, DEFAULT_FIM_SCHEME_ADAPTER); - return new FimScheme(doc, fimSchemeIdentifier, fimSchemeAdapter); + String getRepresentationName(FormDataControl formDataControl) { + return formDataControl.getRepresentations().map(Representations::getPrimaryFormDataRepresentation) + .orElseGet(() -> { + LOG.warn("No entry point found in metadata file for fim data mapping. Trying default."); + return DEFAULT_FORMDATA_REPRESENTATION_NAME; + }); } - private FimScheme buildUnknownScheme() throws ParserConfigurationException { - final Document doc = DocumentBuilderFactory.newInstance().newDocumentBuilder().newDocument(); - final FimSchemeIdentifier unknownFimSchemeIdentifier = FimSchemeIdentifier.fromString(UNKNOWN_SCHEME_NAME); - final FimSchemeAdapter fimSchemeAdapter = fimSchemeAdapterCatalogue.get(unknownFimSchemeIdentifier); - return new FimScheme(doc, unknownFimSchemeIdentifier, fimSchemeAdapter); - } + public FimScheme getScheme(Document document) { + var fimSchemaName = getSchemeName(document); + var fimScheme = schemeHelper.getScheme(fimSchemaName); - public FormData transformDocument(final Document document, final FormData initialFormData) { - final String[] tagParts = document.getDocumentElement().getTagName().split(":"); - final String namespacePrefix = tagParts.length < 2 ? "" : (":" + tagParts[0]); - final String schemeName = document.getDocumentElement().getAttribute("xmlns" + namespacePrefix); - if (StringUtils.isEmpty(schemeName)) { - throw new FimException("XML Document does not provide a scheme"); + if (Objects.isNull(fimScheme)) { + LOG.error("Cannot find schema for: {}", fimSchemaName); + return schemeHelper.getDefaultScheme(); } - final FimScheme scheme = getSchemeForIdentifier(schemeName); - final FormData.FormDataBuilder builder = fimDataMapper.apply(document, scheme, initialFormData); - - builder.header(initialFormData.getHeader()); - - return builder.build(); + return fimScheme; } - FimScheme getSchemeForIdentifier(final String fimSchemaName) { - final FimSchemeIdentifier fimSchemeIdentifier = FimSchemeIdentifier.fromString(fimSchemaName); - final FimScheme fimScheme = fimSchemeCatalogue.get(fimSchemeIdentifier); - if (fimScheme == null) { - LOG.error("Cannot find schema for: " + fimSchemaName); - return fimSchemeCatalogue.get(FimSchemeIdentifier.fromString(UNKNOWN_SCHEME_NAME)); - } - return fimScheme; + String getSchemeName(Document doc) { + return Optional.of(DocumentHelper.extractSchemeName(doc)) + .filter(StringUtils::isNotEmpty) + .orElseThrow(() -> new FimException("XML Document does not provide a scheme.")); } -} +} \ No newline at end of file diff --git a/fim-adapter/src/main/java/de/ozgcloud/eingang/fim/HeaderMapper.java b/fim-adapter/src/main/java/de/ozgcloud/eingang/fim/HeaderMapper.java new file mode 100644 index 0000000000000000000000000000000000000000..63befb6637b368805c57cfe354df8d4974ad74ba --- /dev/null +++ b/fim-adapter/src/main/java/de/ozgcloud/eingang/fim/HeaderMapper.java @@ -0,0 +1,36 @@ +package de.ozgcloud.eingang.fim; + +import java.util.List; +import java.util.Map; +import java.util.Optional; + +import org.springframework.stereotype.Component; + +import de.ozgcloud.eingang.common.formdata.FormData; +import lombok.RequiredArgsConstructor; +import lombok.extern.log4j.Log4j2; + +@Log4j2 +@RequiredArgsConstructor +@Component +class HeaderMapper implements FimEngineBasedMapper { + + static final String FORM_NAME_KEY = "F05002753"; + + @Override + public FormData parseFormData(FormData formData) { + return getFormName(formData.getFormData()).map(formName -> addFormName(formData, formName)).orElse(formData); + } + + Optional<String> getFormName(Map<String, Object> formData) { + return FimDataUtil.getValue(formData, List.of("G17003529", "G05001479", "G05001480"), FORM_NAME_KEY); + } + + private FormData addFormName(FormData formData, String formName) { + return formData.toBuilder() + .header(formData.getHeader().toBuilder() + .formName(formName) + .build()) + .build(); + } +} \ No newline at end of file diff --git a/fim-adapter/src/main/java/de/ozgcloud/eingang/fim/UnknownSchemeAdapter.java b/fim-adapter/src/main/java/de/ozgcloud/eingang/fim/UnknownSchemeAdapter.java index d6382f88aba776dafd40c3502c6a0b260b5c2ba0..8c4a1512e0d78cf7c059b548c0c83b3b629f84a2 100644 --- a/fim-adapter/src/main/java/de/ozgcloud/eingang/fim/UnknownSchemeAdapter.java +++ b/fim-adapter/src/main/java/de/ozgcloud/eingang/fim/UnknownSchemeAdapter.java @@ -23,21 +23,27 @@ */ package de.ozgcloud.eingang.fim; -import org.springframework.stereotype.Service; -import org.w3c.dom.Element; - import java.util.Map; import java.util.Optional; -@Service -public class UnknownSchemeAdapter extends FimSchemeAdapter { +import org.springframework.stereotype.Component; +import org.w3c.dom.Element; + +import de.ozgcloud.eingang.fim.common.xml.DocumentHelper; + +@Component +class UnknownSchemeAdapter extends FimSchemeAdapter { + + public static final String UNKNOWN_SCHEME_NAME = "unknown"; + public static final FimSchemeIdentifier IDENTIFIER = FimSchemeIdentifier.fromString(UNKNOWN_SCHEME_NAME); - public FimSchemeIdentifier forIdentifier() { - return FimSchemeIdentifier.fromString(FimService.UNKNOWN_SCHEME_NAME); - } + @Override + public FimSchemeIdentifier getIdentifier() { + return IDENTIFIER; + } - @Override - public Optional<String> getFieldName(Map<String, Element> fieldIndex, String fieldName) { - return Optional.of(fieldName); - } + @Override + public Optional<String> getFieldName(Map<String, Element> fieldIndex, String fieldName) { + return Optional.of(DocumentHelper.getFieldNameWithoutNamespace(fieldName)); + } } diff --git a/fim-adapter/src/main/java/de/ozgcloud/eingang/fim/ZustaendigeStelleMapper.java b/fim-adapter/src/main/java/de/ozgcloud/eingang/fim/ZustaendigeStelleMapper.java index d75a99adc7ca108dc159eab3a96965e7e0c42b85..bb8de3ff65c9bdd2bae4e5a3abeedd99ec8baaed 100644 --- a/fim-adapter/src/main/java/de/ozgcloud/eingang/fim/ZustaendigeStelleMapper.java +++ b/fim-adapter/src/main/java/de/ozgcloud/eingang/fim/ZustaendigeStelleMapper.java @@ -45,19 +45,19 @@ class ZustaendigeStelleMapper implements FimEngineBasedMapper { return formData.getControl().getMetaData() .map(metaData -> metaData.getEntry(XTA_IDENTIFIER_ENTRY_NAME)) .filter(Objects::nonNull) - .map(oeId -> setOrganisationsEinheitId(formData.getZustaendigeStelles(), oeId)) + .map(id -> setOrganisationEinheitId(formData.getZustaendigeStelles(), id)) .map(zustStelle -> formData.toBuilder().zustaendigeStelle(zustStelle).build()) .orElse(formData); } - private ZustaendigeStelle setOrganisationsEinheitId(List<ZustaendigeStelle> stelles, @NonNull String oeid) { - var builder = stelles.isEmpty() ? ZustaendigeStelle.builder() : stelles.getFirst().toBuilder(); + private ZustaendigeStelle setOrganisationEinheitId(List<ZustaendigeStelle> stellen, @NonNull String organisationEinheitId) { + var builder = stellen.isEmpty() ? ZustaendigeStelle.builder() : stellen.getFirst().toBuilder(); - extractOrganisationsEinheitId(oeid).ifPresent(builder::organisationseinheitenId); + extractOrganisationEinheitId(organisationEinheitId).ifPresent(builder::organisationseinheitenId); return builder.build(); } - Optional<String> extractOrganisationsEinheitId(@NonNull String xtaIdentifier) { + Optional<String> extractOrganisationEinheitId(@NonNull String xtaIdentifier) { var idx = xtaIdentifier.indexOf(":"); if (idx < 0) { return Optional.empty(); diff --git a/fim-adapter/src/main/java/de/ozgcloud/eingang/fim/common/errorhandling/FimException.java b/fim-adapter/src/main/java/de/ozgcloud/eingang/fim/common/errorhandling/FimException.java new file mode 100644 index 0000000000000000000000000000000000000000..68be9eb443298ed45cafcbe646f73b85de9c6519 --- /dev/null +++ b/fim-adapter/src/main/java/de/ozgcloud/eingang/fim/common/errorhandling/FimException.java @@ -0,0 +1,12 @@ +package de.ozgcloud.eingang.fim.common.errorhandling; + +import de.ozgcloud.eingang.common.errorhandling.TechnicalException; + +public class FimException extends TechnicalException { + + private static final long serialVersionUID = 1L; + + public FimException(String message) { + super(message); + } +} diff --git a/fim-adapter/src/main/java/de/ozgcloud/eingang/fim/common/xml/DocumentHelper.java b/fim-adapter/src/main/java/de/ozgcloud/eingang/fim/common/xml/DocumentHelper.java new file mode 100644 index 0000000000000000000000000000000000000000..2368cd4ddd96ed23fe11e3c8553391d78fd19e22 --- /dev/null +++ b/fim-adapter/src/main/java/de/ozgcloud/eingang/fim/common/xml/DocumentHelper.java @@ -0,0 +1,69 @@ +package de.ozgcloud.eingang.fim.common.xml; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.util.Optional; +import java.util.stream.IntStream; +import java.util.stream.Stream; + +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.ParserConfigurationException; + +import org.apache.commons.lang3.StringUtils; +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; +import org.w3c.dom.Text; +import org.xml.sax.SAXException; + +import lombok.AccessLevel; +import lombok.NoArgsConstructor; + +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public class DocumentHelper { + + public static Document parse(InputStream inputStream) throws ParserConfigurationException, IOException, SAXException { + return getDocumentBuilder().parse(inputStream); + } + + public static Document parse(File file) throws ParserConfigurationException, IOException, SAXException { + return getDocumentBuilder().parse(file); + } + + public static DocumentBuilder getDocumentBuilder() throws ParserConfigurationException { + return DocumentBuilderFactory.newInstance().newDocumentBuilder(); + } + + public static String extractSchemeName(Document doc) { + var tagParts = doc.getDocumentElement().getTagName().split(":"); + var namespacePrefix = tagParts.length < 2 ? "" : (":" + tagParts[0]); + return doc.getDocumentElement().getAttribute("xmlns" + namespacePrefix); + } + + public static Stream<Element> getChildNodes(NodeList childNodes) { + return IntStream.range(0, childNodes.getLength()) + .mapToObj(childNodes::item) + .filter(Element.class::isInstance) + .map(Element.class::cast); + } + + public static boolean isTextNode(Node node) { + return node.getChildNodes().getLength() == 1 && node.getChildNodes().item(0) instanceof Text; + } + + public static String getFieldNameWithoutNamespace(String nodeName) { + var fieldNameParts = nodeName.split(":"); + return fieldNameParts[fieldNameParts.length - 1]; + } + + public static Optional<String> getChildElement(Element element, String tagName) { + var nameTags = element.getElementsByTagName(tagName); + if (nameTags.getLength() != 1) { + return Optional.empty(); + } + return Optional.ofNullable(nameTags.item(0).getTextContent()).map(StringUtils::trim); + } +} \ No newline at end of file diff --git a/fim-adapter/src/main/resources/fim-s17000652_1.4/S17000652V1.4_xfall.xsd b/fim-adapter/src/main/resources/fim-s17000652_1.4/S17000652V1.4_xfall.xsd index c5c859d0a2fec4d7fb668678afd680cbbcbf0088..abcad3097da351fb7bda11a134e75647055efac0 100644 --- a/fim-adapter/src/main/resources/fim-s17000652_1.4/S17000652V1.4_xfall.xsd +++ b/fim-adapter/src/main/resources/fim-s17000652_1.4/S17000652V1.4_xfall.xsd @@ -1,32 +1,1406 @@ -<?xml version="1.0" encoding="UTF-8"?><xs:schema xmlns:xfd="urn:xoev-de:xfall:standard:fim-s17000652_1.4" xmlns:xs="http://www.w3.org/2001/XMLSchema" attributeFormDefault="unqualified" elementFormDefault="qualified" targetNamespace="urn:xoev-de:xfall:standard:fim-s17000652_1.4" version="V1.4"><xs:element name="fim.S17000652.17000652001004"><xs:complexType><xs:sequence><xs:element name="G17003529" type="xfd:G17003529"><xs:annotation><xs:documentation><name>EfA|SH Standard</name><bezug>tbd</bezug></xs:documentation></xs:annotation></xs:element><xs:element name="F17009191" type="xs:boolean"><xs:annotation><xs:documentation><name>Anzeige durch Person </name><definition>Wahrheitswert: ja oder nein
 -</definition><bezug>Art. 8 GG;§ 11 VershFG SG
 -</bezug></xs:documentation></xs:annotation></xs:element><xs:element minOccurs="0" name="G17002112" type="xfd:G17002112"><xs:annotation><xs:documentation><name>Anzeigenersteller:in</name><bezug>Art. 8 GG; § 11 VershFG SG</bezug></xs:documentation></xs:annotation></xs:element><xs:element minOccurs="0" name="G17005403" type="xfd:G17005403"><xs:annotation><xs:documentation><name>Organisation </name><definition>Angaben zur Organisation, welche die Versammlung durchführen möchte</definition><bezug>Art. 8 GG;§ 11 VershFG SG
 -</bezug></xs:documentation></xs:annotation></xs:element><xs:element name="F17003371" type="xs:string"><xs:annotation><xs:documentation><name>Anzeigenart</name><bezug>Art. 8 GG; § 11 VershFG SG</bezug></xs:documentation></xs:annotation></xs:element><xs:element minOccurs="0" name="G17005404" type="xfd:G17005404"><xs:annotation><xs:documentation><name>Versammlung (ortsfest)</name><bezug>Art. 8 GG ; § 11 VershFG SH</bezug></xs:documentation></xs:annotation></xs:element><xs:element minOccurs="0" name="G17005410" type="xfd:G17005410"><xs:annotation><xs:documentation><name>Versammlung (Aufzug)</name><bezug>Art. 8 GG ; § 11 VersFG SH</bezug></xs:documentation></xs:annotation></xs:element></xs:sequence></xs:complexType></xs:element><xs:complexType name="G17003529"><xs:sequence><xs:element name="G05001479" type="xfd:G05001479"><xs:annotation><xs:documentation><name>nachrichtenkopf</name><beschreibung>Der Nachrichtenkopf beinhaltet alle erforderlichen Informationen für die Zustellung und Verifizierung mit Hilfe des DVDV.</beschreibung><bezug>DVDV</bezug></xs:documentation></xs:annotation></xs:element><xs:element name="F17005454" type="xs:boolean"><xs:annotation><xs:documentation><name>Datenschutzhinweis DSGVO</name><bezug>tbd</bezug></xs:documentation></xs:annotation></xs:element><xs:element name="F17005455" type="xs:boolean"><xs:annotation><xs:documentation><name>Zustimmung zu einem digitalen Bescheid</name><bezug>tbd</bezug></xs:documentation></xs:annotation></xs:element><xs:element name="F17005533" type="xs:string"><xs:annotation><xs:documentation><name>UUID</name><bezug>tbd</bezug></xs:documentation></xs:annotation></xs:element></xs:sequence></xs:complexType><xs:complexType name="G05001479"><xs:sequence><xs:element name="G05001480" type="xfd:G05001480"><xs:annotation><xs:documentation><name>identifikation.nachricht</name><bezug>DVDV</bezug></xs:documentation></xs:annotation></xs:element><xs:element name="G05001481" type="xfd:G05001481"><xs:annotation><xs:documentation><name>Leser</name><bezug>DVDV</bezug></xs:documentation></xs:annotation></xs:element><xs:element name="G05001482" type="xfd:G05001482"><xs:annotation><xs:documentation><name>Autor</name><bezug>DVDV</bezug></xs:documentation></xs:annotation></xs:element></xs:sequence></xs:complexType><xs:complexType name="G05001480"><xs:sequence><xs:element name="F05002750" type="xs:string"><xs:annotation><xs:documentation><name>nachrichtenUUID</name><bezug>DVDV</bezug></xs:documentation></xs:annotation></xs:element><xs:element name="F05002751" type="xs:string"><xs:annotation><xs:documentation><name>erstellungszeitpunkt</name><bezug>DVDV</bezug></xs:documentation></xs:annotation></xs:element><xs:element name="F05002752" type="xs:string"><xs:annotation><xs:documentation><name>nachrichtentyp</name><bezug>DVDV</bezug></xs:documentation></xs:annotation></xs:element><xs:element name="F05002753" type="xs:string"><xs:annotation><xs:documentation><name>dienstname</name><bezug>DVDV</bezug></xs:documentation></xs:annotation></xs:element></xs:sequence></xs:complexType><xs:complexType name="G05001481"><xs:sequence><xs:element name="F05002754" type="xs:string"><xs:annotation><xs:documentation><name>Organisationsname</name><bezug>DVDV</bezug></xs:documentation></xs:annotation></xs:element><xs:element name="F05002755" type="xs:string"><xs:annotation><xs:documentation><name>Organisationsschlüssel</name><bezug>DVDV</bezug></xs:documentation></xs:annotation></xs:element><xs:element name="F05002756" type="xs:string"><xs:annotation><xs:documentation><name>Kategorie</name><bezug>DVDV</bezug></xs:documentation></xs:annotation></xs:element></xs:sequence></xs:complexType><xs:complexType name="G05001482"><xs:sequence><xs:element name="F05002754" type="xs:string"><xs:annotation><xs:documentation><name>Organisationsname</name><bezug>DVDV</bezug></xs:documentation></xs:annotation></xs:element><xs:element name="F05002755" type="xs:string"><xs:annotation><xs:documentation><name>Organisationsschlüssel</name><bezug>DVDV</bezug></xs:documentation></xs:annotation></xs:element><xs:element name="F05002756" type="xs:string"><xs:annotation><xs:documentation><name>Kategorie</name><bezug>DVDV</bezug></xs:documentation></xs:annotation></xs:element></xs:sequence></xs:complexType><xs:complexType name="G17002112"><xs:sequence><xs:element name="F60000228" type="xs:string"><xs:annotation><xs:documentation><name>Vornamen</name><beschreibung>Laut BSI TR-03123 soll Vorname ≤ 80 Zeichen betragen.
 -Laut PAuswV soll Vorname nicht mehr als 26 Zeichen bzw. 2*40 = 80 Zeichen betragen.</beschreibung><definition>Plural zu Vorname</definition><bezug>§ 5 (2) Nr. 2 PAuswG vom 21.6.2019; Anhang 3 PAuswV vom 28.9.2017; 
 -Tabelle 9 BSI TR-03123 Version 1.5.1; XOEV.Kernkomponente.NameNatuerlichePerson.vorname vom 31.08.2020</bezug></xs:documentation></xs:annotation></xs:element><xs:element name="F60000227" type="xs:string"><xs:annotation><xs:documentation><name>Familienname</name><beschreibung>Laut BSI TR-03123 soll die Gesamtlänge für Familienname, Titel und Geburtsname nicht mehr als 120 Zeichen betragen. Laut PAuswV soll Name (Familienname und Geburtsname) nicht mehr als 2*26 = 52 Zeichen bzw. 3*40 = 120 Zeichen betragen.</beschreibung><definition>Familienname einer natürlichen Person bestehend aus Nachname, Zuname bzw. Familienname.</definition><bezug>§ 5 (2) Nr. 1 PAuswG vom 21.6.2019; Anhang 3 PAuswV vom 28.9.2017; Tabelle 9 BSI TR-03123 Version 1.5.1; XOEV.Kernkomponente.NameNatuerlichePerson.familienname vom 31.01.2020</bezug></xs:documentation></xs:annotation></xs:element><xs:element name="G60000086" type="xfd:G60000086"><xs:annotation><xs:documentation><name>Anschrift Inland Straßenanschrift</name></xs:documentation></xs:annotation></xs:element><xs:element minOccurs="0" name="F60000240" type="xs:string"><xs:annotation><xs:documentation><name>Telefon</name><beschreibung>Dieses Feld wurde angelehnt an ITU E.123. Eine Prüfung über ein Pattern erfolgt nicht, um den Eingebenden nicht zu überfordern.</beschreibung><definition>Telefonnummer</definition><bezug>ITU E.123</bezug></xs:documentation></xs:annotation></xs:element><xs:element minOccurs="0" name="F60000242" type="xs:string"><xs:annotation><xs:documentation><name>E-Mail</name><definition>Elektronische Adresse zum Senden und Empfangen von digitalen Nachrichten (E-Mails) z.B. MaxMustermann@email.de</definition><bezug>RFC 5322; RFC 5321</bezug></xs:documentation></xs:annotation></xs:element><xs:element name="F17009011" type="xs:boolean"><xs:annotation><xs:documentation><name>Auswahl Anzeigenersteller:in = Verantwortliche Versammlungsleiter:in</name><definition>Angabe ob Sie als Anzeigenersteller:in ebenfalls Verantwortliche Versammlungsleiter:in sind</definition><bezug>Art. 8 GG; § 11 VershFG SG</bezug></xs:documentation></xs:annotation></xs:element><xs:element minOccurs="0" name="G17002127" type="xfd:G17002127"><xs:annotation><xs:documentation><name>Verantwortliche Versammlungsleiter:in</name><bezug>Art. 8 GG; § 11 VershFG SG</bezug></xs:documentation></xs:annotation></xs:element></xs:sequence></xs:complexType><xs:complexType name="G60000086"><xs:sequence><xs:element name="F60000243" type="xs:string"><xs:annotation><xs:documentation><name>Straße</name><beschreibung>Kompatibilität zu EPA in TR XhD v 1.4 sollte Feldlänge min. 50. Bei XInneres 8 ist die Feldlänge <= 55 Zeichen.</beschreibung><bezug>XInneres.Meldeanschrift.strasse Version 8</bezug></xs:documentation></xs:annotation></xs:element><xs:element minOccurs="0" name="F60000244" type="xs:string"><xs:annotation><xs:documentation><name>Hausnummer</name><beschreibung>Die Modellierung aus XInneres wurde nicht 1:1 übernommen, um die Komplexität für die Ausfüllenden nicht zu hoch zu setzen. Es wurde darauf verzichtet für das Ende von Hausnummernbereichen eigene Felder zu modellieren. Daher ist die Feldlänge hier heraufgesetzt und eine entsprechende Beschreibung wurde eingefügt. Die Feldlänge setzt sich aus der maximalen Feldlänge zweier Hausnummern (jeweils 4), zweier Buchstaben (jeweils 1) und eines Zeichen (-) zusammen.</beschreibung><definition>Es sind die Ziffern und Buchstabeneiner Hausnummer anzugeben. Eine Hausnummer dient der genauen Lokalisierung eines Grundstücks, Gebäudes oder Gebäudeteils (Eingang) in einer Straße. Geben Sie Hausnummernbereiche immer nach folgendem Beispiel ohne Leerzeichen an: 12a-14d</definition><bezug>XInneres.Meldeanschrift.hausnummer Version 8</bezug></xs:documentation></xs:annotation></xs:element><xs:element name="F60000246" type="xs:string"><xs:annotation><xs:documentation><name>Postleitzahl</name><definition>Es ist die Postleitzahl anzugeben.
 -
 -Der Typ dieses Elements ist eine Einschränkung des Basistyps String.Latin.</definition><bezug>XInneres.Meldeanschrift.postleitzahl Version 8</bezug></xs:documentation></xs:annotation></xs:element><xs:element name="F60000247" type="xs:string"><xs:annotation><xs:documentation><name>Ort</name><beschreibung>Kompatibilität zu EPA in TR XhD v 1.4 sollte Feldlänge min. 44. Laut PAuswV 2*25 = 50 Zeichen. Laut Xinneres.Meldeanschrift.Wohnort Version 8 = 40 Zeichen.
 -Laut BSI TR-03123 ≤ 105 Zeichen.</beschreibung><definition>Enthält den Namen eines Ortes (Gemeinde, Ortschaft oder Stadt).</definition><bezug>§ 5 (2) Nr. 9 PAuswG vom 21.6.2019; Anhang 3 Abschnitt 1 (Wohnort) PAuswV vom 28.9.2017; Tabelle 11 BSI TR-03123, Version 1.5.1; Xinneres.Meldeanschrift.Wohnort Version 8; XOEV.Kernkomponente.Anschrift.ort vom 31.01.2020</bezug></xs:documentation></xs:annotation></xs:element><xs:element minOccurs="0" name="F60000248" type="xs:string"><xs:annotation><xs:documentation><name>Anschrift Zusatzangaben</name><definition>Es sind Zusatzangaben zur Anschrift anzugeben, z.B. Hinterhaus, Gartenhaus.
 -</definition><bezug>XInneres.Meldeanschrift.zusatzangaben Version 8</bezug></xs:documentation></xs:annotation></xs:element></xs:sequence></xs:complexType><xs:complexType name="G17002127"><xs:sequence><xs:element name="F60000228" type="xs:string"><xs:annotation><xs:documentation><name>Vornamen</name><beschreibung>Laut BSI TR-03123 soll Vorname ≤ 80 Zeichen betragen.
 -Laut PAuswV soll Vorname nicht mehr als 26 Zeichen bzw. 2*40 = 80 Zeichen betragen.</beschreibung><definition>Plural zu Vorname</definition><bezug>§ 5 (2) Nr. 2 PAuswG vom 21.6.2019; Anhang 3 PAuswV vom 28.9.2017; 
 -Tabelle 9 BSI TR-03123 Version 1.5.1; XOEV.Kernkomponente.NameNatuerlichePerson.vorname vom 31.08.2020</bezug></xs:documentation></xs:annotation></xs:element><xs:element name="F60000227" type="xs:string"><xs:annotation><xs:documentation><name>Familienname</name><beschreibung>Laut BSI TR-03123 soll die Gesamtlänge für Familienname, Titel und Geburtsname nicht mehr als 120 Zeichen betragen. Laut PAuswV soll Name (Familienname und Geburtsname) nicht mehr als 2*26 = 52 Zeichen bzw. 3*40 = 120 Zeichen betragen.</beschreibung><definition>Familienname einer natürlichen Person bestehend aus Nachname, Zuname bzw. Familienname.</definition><bezug>§ 5 (2) Nr. 1 PAuswG vom 21.6.2019; Anhang 3 PAuswV vom 28.9.2017; Tabelle 9 BSI TR-03123 Version 1.5.1; XOEV.Kernkomponente.NameNatuerlichePerson.familienname vom 31.01.2020</bezug></xs:documentation></xs:annotation></xs:element><xs:element name="G60000086" type="xfd:G60000086"><xs:annotation><xs:documentation><name>Anschrift Inland Straßenanschrift</name></xs:documentation></xs:annotation></xs:element><xs:element minOccurs="0" name="F60000242" type="xs:string"><xs:annotation><xs:documentation><name>E-Mail</name><definition>Elektronische Adresse zum Senden und Empfangen von digitalen Nachrichten (E-Mails) z.B. MaxMustermann@email.de</definition><bezug>RFC 5322; RFC 5321</bezug></xs:documentation></xs:annotation></xs:element><xs:element minOccurs="0" name="F60000240" type="xs:string"><xs:annotation><xs:documentation><name>Telefon</name><beschreibung>Dieses Feld wurde angelehnt an ITU E.123. Eine Prüfung über ein Pattern erfolgt nicht, um den Eingebenden nicht zu überfordern.</beschreibung><definition>Telefonnummer</definition><bezug>ITU E.123</bezug></xs:documentation></xs:annotation></xs:element><xs:element minOccurs="0" name="F17011808" type="xs:string"><xs:annotation><xs:documentation><name>Telefonische Erreichbarkeit am Tag der Veranstaltung</name><bezug>§ 11 VershFG</bezug></xs:documentation></xs:annotation></xs:element></xs:sequence></xs:complexType><xs:complexType name="G17005403"><xs:sequence><xs:element name="G17007200" type="xfd:G17007200"><xs:annotation><xs:documentation><name>Daten der anzeigenden Organisation</name><bezug>Art. 8 GG ;§ 11 VershFG SH</bezug></xs:documentation></xs:annotation></xs:element><xs:element name="G17007201" type="xfd:G17007201"><xs:annotation><xs:documentation><name>Ansprechperson der Organisation</name><definition>Sie sollten als Versammlungsleitung oder veranstaltende Person oder Organisation Ihre Telefonnummer oder E-Mail-Adresse, unter der Sie vor und während der Versammlung erreichbar sind, angeben. Dies dient der schnellen, einfachen und vertrauensvollen Zusammenarbeit mit der Versammlungsbehörde und der Sicherstellung des Schutzes Ihrer Versammlung.</definition><bezug>Art. 8 GG;§ 11 VershFG SG</bezug></xs:documentation></xs:annotation></xs:element><xs:element name="G17002127" type="xfd:G17002127"><xs:annotation><xs:documentation><name>Verantwortliche Versammlungsleiter:in</name><bezug>Art. 8 GG; § 11 VershFG SG</bezug></xs:documentation></xs:annotation></xs:element></xs:sequence></xs:complexType><xs:complexType name="G17007200"><xs:sequence><xs:element name="F60000319" type="xs:string"><xs:annotation><xs:documentation><name>Eingetragener Name / Organisationsname</name><beschreibung>Laut XGewerbeanzeige.Betrieb.eingetragenerName soll der eingetragene Name 1-1000 Zeichen betragen.</beschreibung><definition>Die im Handels- oder Genossenschaftsregister eingetragene Firma eines wirtschaftlich Tätigen bzw. einer wirtschaftlichen Tätigkeit (z. B. eingetragenes Einzelunternehmen,eingetragene Zweigniederlassung) bzw. der im Vereinsregister, Partnerschaftsregister oder Stiftungsverzeichnis eingetragene Name.
 -
 -Der eingetragene Name kann auch in einem Register festgehalten sein, welches in einem anderen Staat geführt wird.
 -
 -Der eingetragene Name ist abzugrenzen von der Geschäftsbezeichnung. 
 -
 -Das Kerndatenobjekt bildet auch die Namen juristischer Personen, Personengesellschaften oder sonstiger Personenvereinigungen ab, die nicht in einem Register, aber kraft Gesetz geführt werden.</definition><bezug>XOEV.Kernkomponente.NameOrganisation.name vom 01.08.2017; XGewerbeanzeige.Betrieb.eingetragenerName Version 2.2; XUnternehmen.Kerndatenmodell.Eingetragener Name Version 1.1</bezug></xs:documentation></xs:annotation></xs:element><xs:element minOccurs="0" name="F17011809" type="xs:string"><xs:annotation><xs:documentation><name>Organisationseinheit</name><definition>Optionale Angabe der Organisationseinheit</definition><bezug>Art. 8 GG;§ 11 VershFG SG</bezug></xs:documentation></xs:annotation></xs:element><xs:element name="G60000086" type="xfd:G60000086"><xs:annotation><xs:documentation><name>Anschrift Inland Straßenanschrift</name><definition>Angaben für die Adressierung im Inland, soweit es sich um die Anschrift eines Gebäudes handelt.</definition><bezug>urn:xoevde:xunternehmen:kerndatenobjekt:anschriftinlandstrassenanschrift</bezug></xs:documentation></xs:annotation></xs:element></xs:sequence></xs:complexType><xs:complexType name="G60000086"><xs:sequence><xs:element name="F60000243" type="xs:string"><xs:annotation><xs:documentation><name>Straße</name><beschreibung>Kompatibilität zu EPA in TR XhD v 1.4 sollte Feldlänge min. 50. Bei XInneres 8 ist die Feldlänge <= 55 Zeichen.</beschreibung><bezug>XInneres.Meldeanschrift.strasse Version 8</bezug></xs:documentation></xs:annotation></xs:element><xs:element minOccurs="0" name="F60000244" type="xs:string"><xs:annotation><xs:documentation><name>Hausnummer</name><beschreibung>Die Modellierung aus XInneres wurde nicht 1:1 übernommen, um die Komplexität für die Ausfüllenden nicht zu hoch zu setzen. Es wurde darauf verzichtet für das Ende von Hausnummernbereichen eigene Felder zu modellieren. Daher ist die Feldlänge hier heraufgesetzt und eine entsprechende Beschreibung wurde eingefügt. Die Feldlänge setzt sich aus der maximalen Feldlänge zweier Hausnummern (jeweils 4), zweier Buchstaben (jeweils 1) und eines Zeichen (-) zusammen.</beschreibung><definition>Es sind die Ziffern und Buchstabeneiner Hausnummer anzugeben. Eine Hausnummer dient der genauen Lokalisierung eines Grundstücks, Gebäudes oder Gebäudeteils (Eingang) in einer Straße. Geben Sie Hausnummernbereiche immer nach folgendem Beispiel ohne Leerzeichen an: 12a-14d</definition><bezug>XInneres.Meldeanschrift.hausnummer Version 8</bezug></xs:documentation></xs:annotation></xs:element><xs:element name="F60000246" type="xs:string"><xs:annotation><xs:documentation><name>Postleitzahl</name><definition>Es ist die Postleitzahl anzugeben.
 -
 -Der Typ dieses Elements ist eine Einschränkung des Basistyps String.Latin.</definition><bezug>XInneres.Meldeanschrift.postleitzahl Version 8</bezug></xs:documentation></xs:annotation></xs:element><xs:element name="F60000247" type="xs:string"><xs:annotation><xs:documentation><name>Ort</name><beschreibung>Kompatibilität zu EPA in TR XhD v 1.4 sollte Feldlänge min. 44. Laut PAuswV 2*25 = 50 Zeichen. Laut Xinneres.Meldeanschrift.Wohnort Version 8 = 40 Zeichen. -Laut BSI TR-03123 kleiner gleich 105 Zeichen.</beschreibung><definition>Enthält den Namen eines Ortes (Gemeinde, Ortschaft oder Stadt).</definition><bezug>§ 5 (2) Nr. 9 PAuswG vom 21.6.2019; Anhang 3 Abschnitt 1 (Wohnort) PAuswV vom 28.9.2017; Tabelle 11 BSI TR-03123, Version 1.5.1; Xinneres.Meldeanschrift.Wohnort Version 8; XOEV.Kernkomponente.Anschrift.ort vom 31.01.2020</bezug></xs:documentation></xs:annotation></xs:element><xs:element minOccurs="0" name="F60000248" type="xs:string"><xs:annotation><xs:documentation><name>Anschrift Zusatzangaben</name><definition>Es sind Zusatzangaben zur Anschrift anzugeben, z.B. Hinterhaus, Gartenhaus.
 -</definition><bezug>XInneres.Meldeanschrift.zusatzangaben Version 8</bezug></xs:documentation></xs:annotation></xs:element></xs:sequence></xs:complexType><xs:complexType name="G17007201"><xs:sequence><xs:element name="F60000228" type="xs:string"><xs:annotation><xs:documentation><name>Vornamen</name><beschreibung>Laut BSI TR-03123 soll Vorname <= 80 Zeichen betragen.
 -Laut PAuswV soll Vorname nicht mehr als 26 Zeichen bzw. 2*40 = 80 Zeichen betragen.</beschreibung><definition>Plural zu Vorname</definition><bezug>§ 5 (2) Nr. 2 PAuswG vom 21.6.2019; Anhang 3 PAuswV vom 28.9.2017; 
 -Tabelle 9 BSI TR-03123 Version 1.5.1; XOEV.Kernkomponente.NameNatuerlichePerson.vorname vom 31.08.2020</bezug></xs:documentation></xs:annotation></xs:element><xs:element name="F60000227" type="xs:string"><xs:annotation><xs:documentation><name>Familienname</name><beschreibung>Laut BSI TR-03123 soll die Gesamtlänge für Familienname, Titel und Geburtsname nicht mehr als 120 Zeichen betragen. Laut PAuswV soll Name (Familienname und Geburtsname) nicht mehr als 2*26 = 52 Zeichen bzw. 3*40 = 120 Zeichen betragen.</beschreibung><definition>Familienname einer natürlichen Person bestehend aus Nachname, Zuname bzw. Familienname.</definition><bezug>§ 5 (2) Nr. 1 PAuswG vom 21.6.2019; Anhang 3 PAuswV vom 28.9.2017; Tabelle 9 BSI TR-03123 Version 1.5.1; XOEV.Kernkomponente.NameNatuerlichePerson.familienname vom 31.01.2020</bezug></xs:documentation></xs:annotation></xs:element><xs:element minOccurs="0" name="F60000240" type="xs:string"><xs:annotation><xs:documentation><name>Telefon</name><beschreibung>Dieses Feld wurde angelehnt an ITU E.123. Eine Prüfung über ein Pattern erfolgt nicht, um den Eingebenden nicht zu überfordern.</beschreibung><definition>Telefonnummer</definition><bezug>ITU E.123</bezug></xs:documentation></xs:annotation></xs:element><xs:element minOccurs="0" name="F60000242" type="xs:string"><xs:annotation><xs:documentation><name>E-Mail</name><definition>Elektronische Adresse zum Senden und Empfangen von digitalen Nachrichten (E-Mails) z.B. MaxMustermann@email.de</definition><bezug>RFC 5322; RFC 5321</bezug></xs:documentation></xs:annotation></xs:element></xs:sequence></xs:complexType><xs:complexType name="G17005404"><xs:sequence><xs:element name="G17007202" type="xfd:G17007202"><xs:annotation><xs:documentation><name>Allgemeine Angaben zur Versammlung</name><bezug>Art. 8 GG ; § 11 VershFG SH</bezug></xs:documentation></xs:annotation></xs:element><xs:element name="G17007205" type="xfd:G17007205"><xs:annotation><xs:documentation><name>Weitere Angaben </name><definition>Angaben zur geplanten Durchführung der Versammlung.</definition><bezug>Art. 8 GG ; §§ 9, 11 VersFG SH</bezug></xs:documentation></xs:annotation></xs:element></xs:sequence></xs:complexType><xs:complexType name="G17007202"><xs:sequence><xs:element name="F17003373" type="xs:string"><xs:annotation><xs:documentation><name>Thema der Versammlung</name><bezug>Art. 8 GG; § 11 VershFG SG</bezug></xs:documentation></xs:annotation></xs:element><xs:element minOccurs="0" name="F17011810" type="xs:string"><xs:annotation><xs:documentation><name>Beschreibung der Versammlung</name><bezug>Art. 8 GG ; § 11 VershFG SH</bezug></xs:documentation></xs:annotation></xs:element><xs:element name="F17003377" type="xs:string"><xs:annotation><xs:documentation><name>Versammlungsort</name><bezug>Art. 8 GG; § 11 VershFG SG</bezug></xs:documentation></xs:annotation></xs:element><xs:element minOccurs="0" name="G17005405" type="xfd:G17005405"><xs:annotation><xs:documentation><name>Karte Versammlungsort</name><definition>Anlage eines Kartenausschnitts</definition><bezug>Art. 8 GG; § 11 VershFG SG</bezug></xs:documentation></xs:annotation></xs:element><xs:element name="G17005406" type="xfd:G17005406"><xs:annotation><xs:documentation><name>Zeitraum (Versammlungsanzeige)</name><definition>Gibt den Anfang und das Ende eines Zeitraums an.</definition><bezug>Art. 8 GG; § 11 VershFG SG</bezug></xs:documentation></xs:annotation></xs:element><xs:element minOccurs="0" name="F17011814" type="xs:string"><xs:annotation><xs:documentation><name>Grund für die verspätete Anmeldung</name><definition>Im Falle der nicht fristgemäßen Anmeldung der Versammlung - Optional Grund ergänzen. </definition><bezug>Art. 8 GG ; § 11 VershFG SH</bezug></xs:documentation></xs:annotation></xs:element><xs:element minOccurs="0" name="F17011815" type="xs:string"><xs:annotation><xs:documentation><name>Telefonnummer zur Rücksprache der verspäteten Anmeldung</name><bezug>Art. 8 GG ; § 11 VershFG SH iVm ITU E.123</bezug></xs:documentation></xs:annotation></xs:element></xs:sequence></xs:complexType><xs:complexType name="G17005405"><xs:sequence><xs:element maxOccurs="5" minOccurs="0" name="F60000296" type="xs:string"><xs:annotation><xs:documentation><name>Nachweis</name><definition>Nachweisdokument, um eine Information zu bestätigen, z.B. Sachkundenachweis.</definition></xs:documentation></xs:annotation></xs:element></xs:sequence></xs:complexType><xs:complexType name="G17005406"><xs:sequence><xs:element name="F60000048" type="xs:date"><xs:annotation><xs:documentation><name>Anfang</name><definition>Beinhaltet das Datum des Anfangs eines Zeitraums.</definition><bezug>urn:xoev-de:kosit:xoev:kernkomponente:zeitraum vom 31.08.2020</bezug></xs:documentation></xs:annotation></xs:element><xs:element name="F17001348" type="xs:decimal"><xs:annotation><xs:documentation><name>Uhrzeit Start</name><bezug>div.</bezug></xs:documentation></xs:annotation></xs:element><xs:element name="F60000049" type="xs:date"><xs:annotation><xs:documentation><name>Ende</name><definition>Beinhaltet das Datum des Ende eines Zeitraums.</definition><bezug>urn:xoev-de:kosit:xoev:kernkomponente:zeitraum vom 31.08.2020</bezug></xs:documentation></xs:annotation></xs:element><xs:element name="F17001349" type="xs:decimal"><xs:annotation><xs:documentation><name>Uhrzeit Abschluss</name><bezug>div.</bezug></xs:documentation></xs:annotation></xs:element></xs:sequence></xs:complexType><xs:complexType name="G17007205"><xs:sequence><xs:element name="F17003379" type="xs:integer"><xs:annotation><xs:documentation><name>Anzahl der Teilnehmenden</name><bezug>Art. 8 GG; § 11 VershFG SH</bezug></xs:documentation></xs:annotation></xs:element><xs:element minOccurs="0" name="F17003380" type="xs:integer"><xs:annotation><xs:documentation><name>Anzahl eingeplanter Ordner:innen</name><definition>Empfehlung: 1 Ordner:in je 50 Teilnehmende</definition><bezug>Art. 8 GG; § 11 VershFG SG</bezug></xs:documentation></xs:annotation></xs:element><xs:element minOccurs="0" name="F17003382" type="xs:string"><xs:annotation><xs:documentation><name>Weitere teilnehmende Organisationen</name><bezug>Art. 8 GG; § 11 VershFG SG</bezug></xs:documentation></xs:annotation></xs:element><xs:element name="G17007234" type="xfd:G17007234"><xs:annotation><xs:documentation><name>Aufbauzeit</name><bezug>§§ 11,14 VersFG SH</bezug></xs:documentation></xs:annotation></xs:element><xs:element name="G17007235" type="xfd:G17007235"><xs:annotation><xs:documentation><name>Abbauzeit</name><bezug>§§ 11,14 VersFG SH</bezug></xs:documentation></xs:annotation></xs:element><xs:element minOccurs="0" name="F17003383" type="xs:string"><xs:annotation><xs:documentation><name>Demonstrationsmittel</name><bezug>Art. 8 GG; § 11 VershFG SG</bezug></xs:documentation></xs:annotation></xs:element><xs:element minOccurs="0" name="G17007207" type="xfd:G17007207"><xs:annotation><xs:documentation><name>Zusätzliche Informationen zu den geplanten Demonstrationsmitteln</name><definition>Optionale Schätzung der Anzahl der Fahnen und Transparente.</definition><bezug>Art. 8 GG ; §§ 9, 11 VershFG SH</bezug></xs:documentation></xs:annotation></xs:element><xs:element minOccurs="0" name="F17003384" type="xs:string"><xs:annotation><xs:documentation><name>Lautsprechereinsatz</name><bezug>Art. 8 GG ; § 11 VersFG SG</bezug></xs:documentation></xs:annotation></xs:element><xs:element minOccurs="0" name="G17007208" type="xfd:G17007208"><xs:annotation><xs:documentation><name>Zusätzliche Informationen zum geplanten Lautsprechereinsatz</name><definition>Angaben zum geplanten Einsatz von Lautsprechern und ggf. Transportfahrzeugen (Musikanlagen, Megafone, PKW/LKW usw.)</definition><bezug>Art. 8 GG ; § 11 VersFG SH</bezug></xs:documentation></xs:annotation></xs:element><xs:element maxOccurs="unbounded" minOccurs="0" name="G17007209" type="xfd:G17007209"><xs:annotation><xs:documentation><name>Geplante Bühnen</name><bezug>Art. 8 GG ; § 11 VersFG SH</bezug></xs:documentation></xs:annotation></xs:element><xs:element minOccurs="0" name="G17007210" type="xfd:G17007210"><xs:annotation><xs:documentation><name>Lagepläne / Skizzen der Aufbauten, Bilder / Informationen zu den Demonstrationsmitteln oder sonstige Dokumente/Informationen hochladen</name><bezug>Art. 8 GG ; §§ 9, 11 VersFG SH</bezug></xs:documentation></xs:annotation></xs:element></xs:sequence></xs:complexType><xs:complexType name="G17007234"><xs:sequence><xs:element name="F17011826" type="xs:string"><xs:annotation><xs:documentation><name>Beträgt die Aufbauzeit über 30 Minuten?</name><bezug>Art. 8 GG ; § 11 VersFG SH</bezug></xs:documentation></xs:annotation></xs:element><xs:element minOccurs="0" name="F17011853" type="xs:integer"><xs:annotation><xs:documentation><name>Auf-/Abbauzeit > 30 min </name><definition>Wenn die Auf- bzw. Abbauzeit mehr als 30 min beträgt in "F17011826 Beträgt die Aufbauzeit über 30 Minuten?" bzw. in "F17011827 Beträgt die Abbauzeit über 30 Minuten?" = Auswahl in C17001209 = 001 "Ja", wird "F17011853 Auf-/Abbauzeit > 30 min" zu einer Pflichtangabe.
 -</definition><bezug>§§ 11,14 VersFG SH</bezug></xs:documentation></xs:annotation></xs:element></xs:sequence></xs:complexType><xs:complexType name="G17007235"><xs:sequence><xs:element name="F17011827" type="xs:string"><xs:annotation><xs:documentation><name>Beträgt die Abbauzeit über 30 Minuten?</name><bezug>Art. 8 GG ; § 11 VersFG SH</bezug></xs:documentation></xs:annotation></xs:element><xs:element minOccurs="0" name="F17011853" type="xs:integer"><xs:annotation><xs:documentation><name>Auf-/Abbauzeit > 30 min </name><definition>Wenn die Auf- bzw. Abbauzeit mehr als 30 min beträgt in "F17011826 Beträgt die Aufbauzeit über 30 Minuten?" bzw. in "F17011827 Beträgt die Abbauzeit über 30 Minuten?" = Auswahl in C17001209 = 001 "Ja", wird "F17011853 Auf-/Abbauzeit > 30 min" zu einer Pflichtangabe.
 -</definition><bezug>§§ 11,14 VersFG SH</bezug></xs:documentation></xs:annotation></xs:element></xs:sequence></xs:complexType><xs:complexType name="G17007207"><xs:sequence><xs:element minOccurs="0" name="F17011818" type="xs:integer"><xs:annotation><xs:documentation><name>Anzahl Transparente</name><bezug>Art. 8 GG ; § 11 VersFG SH</bezug></xs:documentation></xs:annotation></xs:element><xs:element minOccurs="0" name="F17011819" type="xs:integer"><xs:annotation><xs:documentation><name>Anzahl Fahnen</name><bezug>Art. 8 GG ; § 11 VersFG SH</bezug></xs:documentation></xs:annotation></xs:element></xs:sequence></xs:complexType><xs:complexType name="G17007208"><xs:sequence><xs:element minOccurs="0" name="F17011820" type="xs:integer"><xs:annotation><xs:documentation><name>Anzahl Lautsprecher(anlagen)</name><bezug>Art. 8 GG ; § 11 VersFG SH</bezug></xs:documentation></xs:annotation></xs:element><xs:element minOccurs="0" name="F17011821" type="xs:integer"><xs:annotation><xs:documentation><name>Anzahl Megafone</name><bezug>Art. 8 GG ; § 11 VersFG SH</bezug></xs:documentation></xs:annotation></xs:element><xs:element minOccurs="0" name="F17011822" type="xs:integer"><xs:annotation><xs:documentation><name>Anzahl PKW</name><bezug>Art. 8 GG ; § 11 VersFG SH</bezug></xs:documentation></xs:annotation></xs:element><xs:element minOccurs="0" name="F17011824" type="xs:integer"><xs:annotation><xs:documentation><name>Anzahl LKW</name><bezug>Art. 8 GG ; § 11 VersFG SH</bezug></xs:documentation></xs:annotation></xs:element><xs:element minOccurs="0" name="F17011823" type="xs:decimal"><xs:annotation><xs:documentation><name>Gewicht LKW</name><bezug>Art. 8 GG ; § 11 VersFG SH</bezug></xs:documentation></xs:annotation></xs:element></xs:sequence></xs:complexType><xs:complexType name="G17007209"><xs:sequence><xs:element name="F17011825" type="xs:boolean"><xs:annotation><xs:documentation><name>Fester Bühnenaufbau? </name><definition>Wahrheitswert: Auswahl = "ja" entspricht "Fester Aufbau" - Auswahl ="nein" entspricht "mobile Bühne"</definition><bezug>Art. 8 GG ; § 11 VersFG SH</bezug></xs:documentation></xs:annotation></xs:element><xs:element name="F60000302" type="xs:decimal"><xs:annotation><xs:documentation><name>Länge in m</name></xs:documentation></xs:annotation></xs:element><xs:element name="F60000303" type="xs:decimal"><xs:annotation><xs:documentation><name>Breite in m</name></xs:documentation></xs:annotation></xs:element><xs:element name="F60000311" type="xs:decimal"><xs:annotation><xs:documentation><name>Gewicht in kg</name></xs:documentation></xs:annotation></xs:element></xs:sequence></xs:complexType><xs:complexType name="G17007210"><xs:sequence><xs:element maxOccurs="unbounded" minOccurs="0" name="F60000296" type="xs:string"><xs:annotation><xs:documentation><name>Nachweis</name><definition>Nachweisdokument, um eine Information zu bestätigen, z.B. Sachkundenachweis.</definition></xs:documentation></xs:annotation></xs:element></xs:sequence></xs:complexType><xs:complexType name="G17005410"><xs:sequence><xs:element name="G17007211" type="xfd:G17007211"><xs:annotation><xs:documentation><name>Allgemeine Angaben zum Aufzug</name><bezug>Art. 8 GG ; § 11 VershFG SH</bezug></xs:documentation></xs:annotation></xs:element><xs:element minOccurs="0" name="F17011830" type="xs:string"><xs:annotation><xs:documentation><name>Art der Teilnahme</name><definition>Auswahl Art der Teilnahme</definition><bezug>Art. 8 GG ; § 11 VersFG SH</bezug></xs:documentation></xs:annotation></xs:element><xs:element name="G17005412" type="xfd:G17005412"><xs:annotation><xs:documentation><name>Anfangspunkt</name><bezug>Art. 8 GG ; § 11 VersFG SG</bezug></xs:documentation></xs:annotation></xs:element><xs:element name="G17005501" type="xfd:G17005501"><xs:annotation><xs:documentation><name>Streckenverlauf</name><definition>Angaben zum Streckenverlauf und ggf. Karte hinzufügen</definition><bezug>Art. 8 GG ; § 11 VersFG SG</bezug></xs:documentation></xs:annotation></xs:element><xs:element maxOccurs="20" minOccurs="0" name="G17005411" type="xfd:G17005411"><xs:annotation><xs:documentation><name>Zwischenkundgebung</name><definition>Angaben zu möglichen Zwischenkundgebungen</definition><bezug>Art. 8 GG; § 11 VershFG SG
 -</bezug></xs:documentation></xs:annotation></xs:element><xs:element name="F17009218" type="xs:boolean"><xs:annotation><xs:documentation><name>Anfangspunkt = Endpunkt der Versammlung</name><definition>Wenn die Versammlung am gleichen Ort beginnt an dem Sie auch endet</definition><bezug>Art. 8 GG;§ 11 VershFG SG
 -</bezug></xs:documentation></xs:annotation></xs:element><xs:element minOccurs="0" name="G17005413" type="xfd:G17005413"><xs:annotation><xs:documentation><name>Anschrift Inland Straßenanschrift (Ende)</name><bezug>Art. 8 GG; § 11 VershFG SG</bezug></xs:documentation></xs:annotation></xs:element><xs:element name="G17007205" type="xfd:G17007205"><xs:annotation><xs:documentation><name>Weitere Angaben </name><definition>Angaben zur geplanten Durchführung der Versammlung.</definition><bezug>Art. 8 GG ; §§ 9, 11 VersFG SH</bezug></xs:documentation></xs:annotation></xs:element></xs:sequence></xs:complexType><xs:complexType name="G17007211"><xs:sequence><xs:element name="F17011828" type="xs:string"><xs:annotation><xs:documentation><name>Thema des Aufzug</name><bezug>Art. 8 GG; § 11 VersFG SG</bezug></xs:documentation></xs:annotation></xs:element><xs:element minOccurs="0" name="F17011829" type="xs:string"><xs:annotation><xs:documentation><name>Beschreibung des Aufzug</name><bezug>Art. 8 GG ; § 11 VersFG SH</bezug></xs:documentation></xs:annotation></xs:element><xs:element name="G17005406" type="xfd:G17005406"><xs:annotation><xs:documentation><name>Zeitraum (Versammlungsanzeige)</name><definition>Gibt den Anfang und das Ende eines Zeitraums an.</definition><bezug>Art. 8 GG; § 11 VershFG SG</bezug></xs:documentation></xs:annotation></xs:element><xs:element minOccurs="0" name="F17011814" type="xs:string"><xs:annotation><xs:documentation><name>Grund für die verspätete Anmeldung</name><definition>Im Falle der nicht fristgemäßen Anmeldung der Versammlung - Optional Grund ergänzen. </definition><bezug>Art. 8 GG ; § 11 VershFG SH</bezug></xs:documentation></xs:annotation></xs:element><xs:element minOccurs="0" name="F17011815" type="xs:string"><xs:annotation><xs:documentation><name>Telefonnummer zur Rücksprache der verspäteten Anmeldung</name><bezug>Art. 8 GG ; § 11 VershFG SH iVm ITU E.123</bezug></xs:documentation></xs:annotation></xs:element></xs:sequence></xs:complexType><xs:complexType name="G17005412"><xs:sequence><xs:element name="G60000086" type="xfd:G60000086"><xs:annotation><xs:documentation><name>Anschrift Inland Straßenanschrift</name><definition>Angaben für die Adressierung im Inland, soweit es sich um die Anschrift eines Gebäudes handelt.</definition><bezug>urn:xoevde:xunternehmen:kerndatenobjekt:anschriftinlandstrassenanschrift</bezug></xs:documentation></xs:annotation></xs:element><xs:element minOccurs="0" name="G17005405" type="xfd:G17005405"><xs:annotation><xs:documentation><name>Karte Versammlungsort</name><definition>Anlage eines Kartenausschnitts</definition><bezug>Art. 8 GG; § 11 VershFG SG</bezug></xs:documentation></xs:annotation></xs:element></xs:sequence></xs:complexType><xs:complexType name="G17005501"><xs:sequence><xs:element name="F17009317" type="xs:string"><xs:annotation><xs:documentation><name>Beschreibung Streckenverlauf </name><definition>Freitextfeld zum Streckenverlauf.</definition><bezug>Art. 8 GG ; § 11 VersFG SG
 -</bezug></xs:documentation></xs:annotation></xs:element><xs:element minOccurs="0" name="G17007212" type="xfd:G17007212"><xs:annotation><xs:documentation><name>Karte Streckenverlauf</name><definition>Anlage eines Kartenausschnitts</definition><bezug>Art. 8 GG; § 11 VershFG SG</bezug></xs:documentation></xs:annotation></xs:element></xs:sequence></xs:complexType><xs:complexType name="G17007212"><xs:sequence><xs:element maxOccurs="5" minOccurs="0" name="F60000296" type="xs:string"><xs:annotation><xs:documentation><name>Nachweis</name><definition>Nachweisdokument, um eine Information zu bestätigen, z.B. Sachkundenachweis.</definition></xs:documentation></xs:annotation></xs:element></xs:sequence></xs:complexType><xs:complexType name="G17005411"><xs:sequence><xs:element name="G17004014" type="xfd:G17004014"><xs:annotation><xs:documentation><name>Zeitraum (Versammlungsanzeige)</name><definition>Gibt den Anfang und das Ende eines Zeitraums an.</definition><bezug>Art. 8 GG; § 11 VershFG SG</bezug></xs:documentation></xs:annotation></xs:element><xs:element name="G60000086" type="xfd:G60000086"><xs:annotation><xs:documentation><name>Anschrift Inland Straßenanschrift</name><definition>Angaben für die Adressierung im Inland, soweit es sich um die Anschrift eines Gebäudes handelt.</definition><bezug>urn:xoevde:xunternehmen:kerndatenobjekt:anschriftinlandstrassenanschrift</bezug></xs:documentation></xs:annotation></xs:element><xs:element minOccurs="0" name="G17005405" type="xfd:G17005405"><xs:annotation><xs:documentation><name>Karte Versammlungsort</name><definition>Anlage eines Kartenausschnitts</definition><bezug>Art. 8 GG; § 11 VershFG SG</bezug></xs:documentation></xs:annotation></xs:element></xs:sequence></xs:complexType><xs:complexType name="G17004014"><xs:sequence><xs:element name="F60000048" type="xs:date"><xs:annotation><xs:documentation><name>Anfang</name><definition>Beinhaltet das Datum des Anfangs eines Zeitraums.</definition><bezug>urn:xoev-de:kosit:xoev:kernkomponente:zeitraum vom 31.08.2020</bezug></xs:documentation></xs:annotation></xs:element><xs:element name="F17001348" type="xs:decimal"><xs:annotation><xs:documentation><name>Uhrzeit Start</name><bezug>div.</bezug></xs:documentation></xs:annotation></xs:element><xs:element name="F60000049" type="xs:date"><xs:annotation><xs:documentation><name>Ende</name><definition>Beinhaltet das Datum des Ende eines Zeitraums.</definition><bezug>urn:xoev-de:kosit:xoev:kernkomponente:zeitraum vom 31.08.2020</bezug></xs:documentation></xs:annotation></xs:element><xs:element name="F17001349" type="xs:decimal"><xs:annotation><xs:documentation><name>Uhrzeit Abschluss</name><bezug>div.</bezug></xs:documentation></xs:annotation></xs:element></xs:sequence></xs:complexType><xs:complexType name="G17005413"><xs:sequence><xs:element name="F60000243" type="xs:string"><xs:annotation><xs:documentation><name>Straße</name><beschreibung>Kompatibilität zu EPA in TR XhD v 1.4 sollte Feldlänge min. 50. Bei XInneres 8 ist die Feldlänge <= 55 Zeichen.</beschreibung><bezug>XInneres.Meldeanschrift.strasse Version 8</bezug></xs:documentation></xs:annotation></xs:element><xs:element minOccurs="0" name="F60000244" type="xs:string"><xs:annotation><xs:documentation><name>Hausnummer</name><beschreibung>Die Modellierung aus XInneres wurde nicht 1:1 übernommen, um die Komplexität für die Ausfüllenden nicht zu hoch zu setzen. Es wurde darauf verzichtet für das Ende von Hausnummernbereichen eigene Felder zu modellieren. Daher ist die Feldlänge hier heraufgesetzt und eine entsprechende Beschreibung wurde eingefügt. Die Feldlänge setzt sich aus der maximalen Feldlänge zweier Hausnummern (jeweils 4), zweier Buchstaben (jeweils 1) und eines Zeichen (-) zusammen.</beschreibung><definition>Es sind die Ziffern und Buchstabeneiner Hausnummer anzugeben. Eine Hausnummer dient der genauen Lokalisierung eines Grundstücks, Gebäudes oder Gebäudeteils (Eingang) in einer Straße. Geben Sie Hausnummernbereiche immer nach folgendem Beispiel ohne Leerzeichen an: 12a-14d</definition><bezug>XInneres.Meldeanschrift.hausnummer Version 8</bezug></xs:documentation></xs:annotation></xs:element><xs:element name="F60000246" type="xs:string"><xs:annotation><xs:documentation><name>Postleitzahl</name><definition>Es ist die Postleitzahl anzugeben.
 -
 -Der Typ dieses Elements ist eine Einschränkung des Basistyps String.Latin.</definition><bezug>XInneres.Meldeanschrift.postleitzahl Version 8</bezug></xs:documentation></xs:annotation></xs:element><xs:element name="F60000247" type="xs:string"><xs:annotation><xs:documentation><name>Ort</name><beschreibung>Kompatibilität zu EPA in TR XhD v 1.4 sollte Feldlänge min. 44. Laut PAuswV 2*25 = 50 Zeichen. Laut Xinneres.Meldeanschrift.Wohnort Version 8 = 40 Zeichen.
 -Laut BSI TR-03123 ≤ 105 Zeichen.</beschreibung><definition>Enthält den Namen eines Ortes (Gemeinde, Ortschaft oder Stadt).</definition><bezug>§ 5 (2) Nr. 9 PAuswG vom 21.6.2019; Anhang 3 Abschnitt 1 (Wohnort) PAuswV vom 28.9.2017; Tabelle 11 BSI TR-03123, Version 1.5.1; Xinneres.Meldeanschrift.Wohnort Version 8; XOEV.Kernkomponente.Anschrift.ort vom 31.01.2020</bezug></xs:documentation></xs:annotation></xs:element><xs:element minOccurs="0" name="G17005405" type="xfd:G17005405"><xs:annotation><xs:documentation><name>Karte Versammlungsort</name><definition>Anlage eines Kartenausschnitts</definition><bezug>Art. 8 GG; § 11 VershFG SG</bezug></xs:documentation></xs:annotation></xs:element></xs:sequence></xs:complexType></xs:schema> \ No newline at end of file +<?xml version="1.0" encoding="UTF-8"?> +<xs:schema xmlns:xfd="urn:xoev-de:xfall:standard:fim-s17000652_1.4" xmlns:xs="http://www.w3.org/2001/XMLSchema" + attributeFormDefault="unqualified" elementFormDefault="qualified" + targetNamespace="urn:xoev-de:xfall:standard:fim-s17000652_1.4" version="V1.4"> + <xs:element name="fim.S17000652.17000652001004"> + <xs:complexType> + <xs:sequence> + <xs:element name="G17003529" type="xfd:G17003529"> + <xs:annotation> + <xs:documentation> + <name>EfA|SH Standard</name> + <bezug>tbd</bezug> + </xs:documentation> + </xs:annotation> + </xs:element> + <xs:element name="F17009191" type="xs:boolean"> + <xs:annotation> + <xs:documentation> + <name>Anzeige durch Person</name> + <definition>Wahrheitswert: ja oder nein
 + </definition> + <bezug>Art. 8 GG;§ 11 VershFG SG
 + </bezug> + </xs:documentation> + </xs:annotation> + </xs:element> + <xs:element minOccurs="0" name="G17002112" type="xfd:G17002112"> + <xs:annotation> + <xs:documentation> + <name>Anzeigenersteller:in</name> + <bezug>Art. 8 GG; § 11 VershFG SG</bezug> + </xs:documentation> + </xs:annotation> + </xs:element> + <xs:element minOccurs="0" name="G17005403" type="xfd:G17005403"> + <xs:annotation> + <xs:documentation> + <name>Organisation</name> + <definition>Angaben zur Organisation, welche die Versammlung durchführen möchte</definition> + <bezug>Art. 8 GG;§ 11 VershFG SG
 + </bezug> + </xs:documentation> + </xs:annotation> + </xs:element> + <xs:element name="F17003371" type="xs:string"> + <xs:annotation> + <xs:documentation> + <name>Anzeigenart</name> + <bezug>Art. 8 GG; § 11 VershFG SG</bezug> + </xs:documentation> + </xs:annotation> + </xs:element> + <xs:element minOccurs="0" name="G17005404" type="xfd:G17005404"> + <xs:annotation> + <xs:documentation> + <name>Versammlung (ortsfest)</name> + <bezug>Art. 8 GG ; § 11 VershFG SH</bezug> + </xs:documentation> + </xs:annotation> + </xs:element> + <xs:element minOccurs="0" name="G17005410" type="xfd:G17005410"> + <xs:annotation> + <xs:documentation> + <name>Versammlung (Aufzug)</name> + <bezug>Art. 8 GG ; § 11 VersFG SH</bezug> + </xs:documentation> + </xs:annotation> + </xs:element> + </xs:sequence> + </xs:complexType> + </xs:element> + <xs:complexType name="G17003529"> + <xs:sequence> + <xs:element name="G05001479" type="xfd:G05001479"> + <xs:annotation> + <xs:documentation> + <name>nachrichtenkopf</name> + <beschreibung>Der Nachrichtenkopf beinhaltet alle erforderlichen Informationen für die + Zustellung und Verifizierung mit Hilfe des DVDV. + </beschreibung> + <bezug>DVDV</bezug> + </xs:documentation> + </xs:annotation> + </xs:element> + <xs:element name="F17005454" type="xs:boolean"> + <xs:annotation> + <xs:documentation> + <name>Datenschutzhinweis DSGVO</name> + <bezug>tbd</bezug> + </xs:documentation> + </xs:annotation> + </xs:element> + <xs:element name="F17005455" type="xs:boolean"> + <xs:annotation> + <xs:documentation> + <name>Zustimmung zu einem digitalen Bescheid</name> + <bezug>tbd</bezug> + </xs:documentation> + </xs:annotation> + </xs:element> + <xs:element name="F17005533" type="xs:string"> + <xs:annotation> + <xs:documentation> + <name>UUID</name> + <bezug>tbd</bezug> + </xs:documentation> + </xs:annotation> + </xs:element> + </xs:sequence> + </xs:complexType> + <xs:complexType name="G05001479"> + <xs:sequence> + <xs:element name="G05001480" type="xfd:G05001480"> + <xs:annotation> + <xs:documentation> + <name>identifikation.nachricht</name> + <bezug>DVDV</bezug> + </xs:documentation> + </xs:annotation> + </xs:element> + <xs:element name="G05001481" type="xfd:G05001481"> + <xs:annotation> + <xs:documentation> + <name>Leser</name> + <bezug>DVDV</bezug> + </xs:documentation> + </xs:annotation> + </xs:element> + <xs:element name="G05001482" type="xfd:G05001482"> + <xs:annotation> + <xs:documentation> + <name>Autor</name> + <bezug>DVDV</bezug> + </xs:documentation> + </xs:annotation> + </xs:element> + </xs:sequence> + </xs:complexType> + <xs:complexType name="G05001480"> + <xs:sequence> + <xs:element name="F05002750" type="xs:string"> + <xs:annotation> + <xs:documentation> + <name>nachrichtenUUID</name> + <bezug>DVDV</bezug> + </xs:documentation> + </xs:annotation> + </xs:element> + <xs:element name="F05002751" type="xs:string"> + <xs:annotation> + <xs:documentation> + <name>erstellungszeitpunkt</name> + <bezug>DVDV</bezug> + </xs:documentation> + </xs:annotation> + </xs:element> + <xs:element name="F05002752" type="xs:string"> + <xs:annotation> + <xs:documentation> + <name>nachrichtentyp</name> + <bezug>DVDV</bezug> + </xs:documentation> + </xs:annotation> + </xs:element> + <xs:element name="F05002753" type="xs:string"> + <xs:annotation> + <xs:documentation> + <name>dienstname</name> + <bezug>DVDV</bezug> + </xs:documentation> + </xs:annotation> + </xs:element> + </xs:sequence> + </xs:complexType> + <xs:complexType name="G05001481"> + <xs:sequence> + <xs:element name="F05002754" type="xs:string"> + <xs:annotation> + <xs:documentation> + <name>Organisationsname</name> + <bezug>DVDV</bezug> + </xs:documentation> + </xs:annotation> + </xs:element> + <xs:element name="F05002755" type="xs:string"> + <xs:annotation> + <xs:documentation> + <name>Organisationsschlüssel</name> + <bezug>DVDV</bezug> + </xs:documentation> + </xs:annotation> + </xs:element> + <xs:element name="F05002756" type="xs:string"> + <xs:annotation> + <xs:documentation> + <name>Kategorie</name> + <bezug>DVDV</bezug> + </xs:documentation> + </xs:annotation> + </xs:element> + </xs:sequence> + </xs:complexType> + <xs:complexType name="G05001482"> + <xs:sequence> + <xs:element name="F05002754" type="xs:string"> + <xs:annotation> + <xs:documentation> + <name>Organisationsname</name> + <bezug>DVDV</bezug> + </xs:documentation> + </xs:annotation> + </xs:element> + <xs:element name="F05002755" type="xs:string"> + <xs:annotation> + <xs:documentation> + <name>Organisationsschlüssel</name> + <bezug>DVDV</bezug> + </xs:documentation> + </xs:annotation> + </xs:element> + <xs:element name="F05002756" type="xs:string"> + <xs:annotation> + <xs:documentation> + <name>Kategorie</name> + <bezug>DVDV</bezug> + </xs:documentation> + </xs:annotation> + </xs:element> + </xs:sequence> + </xs:complexType> + <xs:complexType name="G17002112"> + <xs:sequence> + <xs:element name="F60000228" type="xs:string"> + <xs:annotation> + <xs:documentation> + <name>Vornamen</name> + <beschreibung>Laut BSI TR-03123 soll Vorname ≤ 80 Zeichen betragen.
 + Laut PAuswV soll Vorname nicht mehr als 26 Zeichen bzw. 2*40 = 80 Zeichen betragen. + </beschreibung> + <definition>Plural zu Vorname</definition> + <bezug>§ 5 (2) Nr. 2 PAuswG vom 21.6.2019; Anhang 3 PAuswV vom 28.9.2017; 
 + Tabelle 9 BSI TR-03123 Version 1.5.1; XOEV.Kernkomponente.NameNatuerlichePerson.vorname vom + 31.08.2020 + </bezug> + </xs:documentation> + </xs:annotation> + </xs:element> + <xs:element name="F60000227" type="xs:string"> + <xs:annotation> + <xs:documentation> + <name>Familienname</name> + <beschreibung>Laut BSI TR-03123 soll die Gesamtlänge für Familienname, Titel und Geburtsname + nicht mehr als 120 Zeichen betragen. Laut PAuswV soll Name (Familienname und Geburtsname) + nicht mehr als 2*26 = 52 Zeichen bzw. 3*40 = 120 Zeichen betragen. + </beschreibung> + <definition>Familienname einer natürlichen Person bestehend aus Nachname, Zuname bzw. + Familienname. + </definition> + <bezug>§ 5 (2) Nr. 1 PAuswG vom 21.6.2019; Anhang 3 PAuswV vom 28.9.2017; Tabelle 9 BSI TR-03123 + Version 1.5.1; XOEV.Kernkomponente.NameNatuerlichePerson.familienname vom 31.01.2020 + </bezug> + </xs:documentation> + </xs:annotation> + </xs:element> + <xs:element name="G60000086" type="xfd:G60000086"> + <xs:annotation> + <xs:documentation> + <name>Anschrift Inland Straßenanschrift</name> + </xs:documentation> + </xs:annotation> + </xs:element> + <xs:element minOccurs="0" name="F60000240" type="xs:string"> + <xs:annotation> + <xs:documentation> + <name>Telefon</name> + <beschreibung>Dieses Feld wurde angelehnt an ITU E.123. Eine Prüfung über ein Pattern erfolgt + nicht, um den Eingebenden nicht zu überfordern. + </beschreibung> + <definition>Telefonnummer</definition> + <bezug>ITU E.123</bezug> + </xs:documentation> + </xs:annotation> + </xs:element> + <xs:element minOccurs="0" name="F60000242" type="xs:string"> + <xs:annotation> + <xs:documentation> + <name>E-Mail</name> + <definition>Elektronische Adresse zum Senden und Empfangen von digitalen Nachrichten (E-Mails) + z.B. MaxMustermann@email.de + </definition> + <bezug>RFC 5322; RFC 5321</bezug> + </xs:documentation> + </xs:annotation> + </xs:element> + <xs:element name="F17009011" type="xs:boolean"> + <xs:annotation> + <xs:documentation> + <name>Auswahl Anzeigenersteller:in = Verantwortliche Versammlungsleiter:in</name> + <definition>Angabe ob Sie als Anzeigenersteller:in ebenfalls Verantwortliche + Versammlungsleiter:in sind + </definition> + <bezug>Art. 8 GG; § 11 VershFG SG</bezug> + </xs:documentation> + </xs:annotation> + </xs:element> + <xs:element minOccurs="0" name="G17002127" type="xfd:G17002127"> + <xs:annotation> + <xs:documentation> + <name>Verantwortliche Versammlungsleiter:in</name> + <bezug>Art. 8 GG; § 11 VershFG SG</bezug> + </xs:documentation> + </xs:annotation> + </xs:element> + </xs:sequence> + </xs:complexType> + <xs:complexType name="G60000086"> + <xs:sequence> + <xs:element name="F60000243" type="xs:string"> + <xs:annotation> + <xs:documentation> + <name>Straße</name> + <beschreibung>Kompatibilität zu EPA in TR XhD v 1.4 sollte Feldlänge min. 50. Bei XInneres 8 ist + die Feldlänge <= 55 Zeichen. + </beschreibung> + <bezug>XInneres.Meldeanschrift.strasse Version 8</bezug> + </xs:documentation> + </xs:annotation> + </xs:element> + <xs:element minOccurs="0" name="F60000244" type="xs:string"> + <xs:annotation> + <xs:documentation> + <name>Hausnummer</name> + <beschreibung>Die Modellierung aus XInneres wurde nicht 1:1 übernommen, um die Komplexität für + die Ausfüllenden nicht zu hoch zu setzen. Es wurde darauf verzichtet für das Ende von + Hausnummernbereichen eigene Felder zu modellieren. Daher ist die Feldlänge hier + heraufgesetzt und eine entsprechende Beschreibung wurde eingefügt. Die Feldlänge setzt sich + aus der maximalen Feldlänge zweier Hausnummern (jeweils 4), zweier Buchstaben (jeweils 1) + und eines Zeichen (-) zusammen. + </beschreibung> + <definition>Es sind die Ziffern und Buchstabeneiner Hausnummer anzugeben. Eine Hausnummer dient + der genauen Lokalisierung eines Grundstücks, Gebäudes oder Gebäudeteils (Eingang) in einer + Straße. Geben Sie Hausnummernbereiche immer nach folgendem Beispiel ohne Leerzeichen an: + 12a-14d + </definition> + <bezug>XInneres.Meldeanschrift.hausnummer Version 8</bezug> + </xs:documentation> + </xs:annotation> + </xs:element> + <xs:element name="F60000246" type="xs:string"> + <xs:annotation> + <xs:documentation> + <name>Postleitzahl</name> + <definition>Es ist die Postleitzahl anzugeben.
 + 
 + Der Typ dieses Elements ist eine Einschränkung des Basistyps String.Latin. + </definition> + <bezug>XInneres.Meldeanschrift.postleitzahl Version 8</bezug> + </xs:documentation> + </xs:annotation> + </xs:element> + <xs:element name="F60000247" type="xs:string"> + <xs:annotation> + <xs:documentation> + <name>Ort</name> + <beschreibung>Kompatibilität zu EPA in TR XhD v 1.4 sollte Feldlänge min. 44. Laut PAuswV 2*25 = + 50 Zeichen. Laut Xinneres.Meldeanschrift.Wohnort Version 8 = 40 Zeichen.
 + Laut BSI TR-03123 ≤ 105 Zeichen. + </beschreibung> + <definition>Enthält den Namen eines Ortes (Gemeinde, Ortschaft oder Stadt).</definition> + <bezug>§ 5 (2) Nr. 9 PAuswG vom 21.6.2019; Anhang 3 Abschnitt 1 (Wohnort) PAuswV vom 28.9.2017; + Tabelle 11 BSI TR-03123, Version 1.5.1; Xinneres.Meldeanschrift.Wohnort Version 8; + XOEV.Kernkomponente.Anschrift.ort vom 31.01.2020 + </bezug> + </xs:documentation> + </xs:annotation> + </xs:element> + <xs:element minOccurs="0" name="F60000248" type="xs:string"> + <xs:annotation> + <xs:documentation> + <name>Anschrift Zusatzangaben</name> + <definition>Es sind Zusatzangaben zur Anschrift anzugeben, z.B. Hinterhaus, Gartenhaus.
 + </definition> + <bezug>XInneres.Meldeanschrift.zusatzangaben Version 8</bezug> + </xs:documentation> + </xs:annotation> + </xs:element> + </xs:sequence> + </xs:complexType> + <xs:complexType name="G17002127"> + <xs:sequence> + <xs:element name="F60000228" type="xs:string"> + <xs:annotation> + <xs:documentation> + <name>Vornamen</name> + <beschreibung>Laut BSI TR-03123 soll Vorname ≤ 80 Zeichen betragen.
 + Laut PAuswV soll Vorname nicht mehr als 26 Zeichen bzw. 2*40 = 80 Zeichen betragen. + </beschreibung> + <definition>Plural zu Vorname</definition> + <bezug>§ 5 (2) Nr. 2 PAuswG vom 21.6.2019; Anhang 3 PAuswV vom 28.9.2017; 
 + Tabelle 9 BSI TR-03123 Version 1.5.1; XOEV.Kernkomponente.NameNatuerlichePerson.vorname vom + 31.08.2020 + </bezug> + </xs:documentation> + </xs:annotation> + </xs:element> + <xs:element name="F60000227" type="xs:string"> + <xs:annotation> + <xs:documentation> + <name>Familienname</name> + <beschreibung>Laut BSI TR-03123 soll die Gesamtlänge für Familienname, Titel und Geburtsname + nicht mehr als 120 Zeichen betragen. Laut PAuswV soll Name (Familienname und Geburtsname) + nicht mehr als 2*26 = 52 Zeichen bzw. 3*40 = 120 Zeichen betragen. + </beschreibung> + <definition>Familienname einer natürlichen Person bestehend aus Nachname, Zuname bzw. + Familienname. + </definition> + <bezug>§ 5 (2) Nr. 1 PAuswG vom 21.6.2019; Anhang 3 PAuswV vom 28.9.2017; Tabelle 9 BSI TR-03123 + Version 1.5.1; XOEV.Kernkomponente.NameNatuerlichePerson.familienname vom 31.01.2020 + </bezug> + </xs:documentation> + </xs:annotation> + </xs:element> + <xs:element name="G60000086" type="xfd:G60000086"> + <xs:annotation> + <xs:documentation> + <name>Anschrift Inland Straßenanschrift</name> + </xs:documentation> + </xs:annotation> + </xs:element> + <xs:element minOccurs="0" name="F60000242" type="xs:string"> + <xs:annotation> + <xs:documentation> + <name>E-Mail</name> + <definition>Elektronische Adresse zum Senden und Empfangen von digitalen Nachrichten (E-Mails) + z.B. MaxMustermann@email.de + </definition> + <bezug>RFC 5322; RFC 5321</bezug> + </xs:documentation> + </xs:annotation> + </xs:element> + <xs:element minOccurs="0" name="F60000240" type="xs:string"> + <xs:annotation> + <xs:documentation> + <name>Telefon</name> + <beschreibung>Dieses Feld wurde angelehnt an ITU E.123. Eine Prüfung über ein Pattern erfolgt + nicht, um den Eingebenden nicht zu überfordern. + </beschreibung> + <definition>Telefonnummer</definition> + <bezug>ITU E.123</bezug> + </xs:documentation> + </xs:annotation> + </xs:element> + <xs:element minOccurs="0" name="F17011808" type="xs:string"> + <xs:annotation> + <xs:documentation> + <name>Telefonische Erreichbarkeit am Tag der Veranstaltung</name> + <bezug>§ 11 VershFG</bezug> + </xs:documentation> + </xs:annotation> + </xs:element> + </xs:sequence> + </xs:complexType> + <xs:complexType name="G17005403"> + <xs:sequence> + <xs:element name="G17007200" type="xfd:G17007200"> + <xs:annotation> + <xs:documentation> + <name>Daten der anzeigenden Organisation</name> + <bezug>Art. 8 GG ;§ 11 VershFG SH</bezug> + </xs:documentation> + </xs:annotation> + </xs:element> + <xs:element name="G17007201" type="xfd:G17007201"> + <xs:annotation> + <xs:documentation> + <name>Ansprechperson der Organisation</name> + <definition>Sie sollten als Versammlungsleitung oder veranstaltende Person oder Organisation + Ihre Telefonnummer oder E-Mail-Adresse, unter der Sie vor und während der Versammlung + erreichbar sind, angeben. Dies dient der schnellen, einfachen und vertrauensvollen + Zusammenarbeit mit der Versammlungsbehörde und der Sicherstellung des Schutzes Ihrer + Versammlung. + </definition> + <bezug>Art. 8 GG;§ 11 VershFG SG</bezug> + </xs:documentation> + </xs:annotation> + </xs:element> + <xs:element name="G17002127" type="xfd:G17002127"> + <xs:annotation> + <xs:documentation> + <name>Verantwortliche Versammlungsleiter:in</name> + <bezug>Art. 8 GG; § 11 VershFG SG</bezug> + </xs:documentation> + </xs:annotation> + </xs:element> + </xs:sequence> + </xs:complexType> + <xs:complexType name="G17007200"> + <xs:sequence> + <xs:element name="F60000319" type="xs:string"> + <xs:annotation> + <xs:documentation> + <name>Eingetragener Name / Organisationsname</name> + <beschreibung>Laut XGewerbeanzeige.Betrieb.eingetragenerName soll der eingetragene Name 1-1000 + Zeichen betragen. + </beschreibung> + <definition>Die im Handels- oder Genossenschaftsregister eingetragene Firma eines wirtschaftlich + Tätigen bzw. einer wirtschaftlichen Tätigkeit (z. B. eingetragenes + Einzelunternehmen,eingetragene Zweigniederlassung) bzw. der im Vereinsregister, + Partnerschaftsregister oder Stiftungsverzeichnis eingetragene Name.
 + 
 + Der eingetragene Name kann auch in einem Register festgehalten sein, welches in einem + anderen Staat geführt wird.
 + 
 + Der eingetragene Name ist abzugrenzen von der Geschäftsbezeichnung. 
 + 
 + Das Kerndatenobjekt bildet auch die Namen juristischer Personen, Personengesellschaften oder + sonstiger Personenvereinigungen ab, die nicht in einem Register, aber kraft Gesetz geführt + werden. + </definition> + <bezug>XOEV.Kernkomponente.NameOrganisation.name vom 01.08.2017; + XGewerbeanzeige.Betrieb.eingetragenerName Version 2.2; + XUnternehmen.Kerndatenmodell.Eingetragener Name Version 1.1 + </bezug> + </xs:documentation> + </xs:annotation> + </xs:element> + <xs:element minOccurs="0" name="F17011809" type="xs:string"> + <xs:annotation> + <xs:documentation> + <name>Organisationseinheit</name> + <definition>Optionale Angabe der Organisationseinheit</definition> + <bezug>Art. 8 GG;§ 11 VershFG SG</bezug> + </xs:documentation> + </xs:annotation> + </xs:element> + <xs:element name="G60000086" type="xfd:G60000086"> + <xs:annotation> + <xs:documentation> + <name>Anschrift Inland Straßenanschrift</name> + <definition>Angaben für die Adressierung im Inland, soweit es sich um die Anschrift eines + Gebäudes handelt. + </definition> + <bezug>urn:xoevde:xunternehmen:kerndatenobjekt:anschriftinlandstrassenanschrift</bezug> + </xs:documentation> + </xs:annotation> + </xs:element> + </xs:sequence> + </xs:complexType> + <xs:complexType name="G60000086"> + <xs:sequence> + <xs:element name="F60000243" type="xs:string"> + <xs:annotation> + <xs:documentation> + <name>Straße</name> + <beschreibung>Kompatibilität zu EPA in TR XhD v 1.4 sollte Feldlänge min. 50. Bei XInneres 8 ist + die Feldlänge <= 55 Zeichen. + </beschreibung> + <bezug>XInneres.Meldeanschrift.strasse Version 8</bezug> + </xs:documentation> + </xs:annotation> + </xs:element> + <xs:element minOccurs="0" name="F60000244" type="xs:string"> + <xs:annotation> + <xs:documentation> + <name>Hausnummer</name> + <beschreibung>Die Modellierung aus XInneres wurde nicht 1:1 übernommen, um die Komplexität für + die Ausfüllenden nicht zu hoch zu setzen. Es wurde darauf verzichtet für das Ende von + Hausnummernbereichen eigene Felder zu modellieren. Daher ist die Feldlänge hier + heraufgesetzt und eine entsprechende Beschreibung wurde eingefügt. Die Feldlänge setzt sich + aus der maximalen Feldlänge zweier Hausnummern (jeweils 4), zweier Buchstaben (jeweils 1) + und eines Zeichen (-) zusammen. + </beschreibung> + <definition>Es sind die Ziffern und Buchstabeneiner Hausnummer anzugeben. Eine Hausnummer dient + der genauen Lokalisierung eines Grundstücks, Gebäudes oder Gebäudeteils (Eingang) in einer + Straße. Geben Sie Hausnummernbereiche immer nach folgendem Beispiel ohne Leerzeichen an: + 12a-14d + </definition> + <bezug>XInneres.Meldeanschrift.hausnummer Version 8</bezug> + </xs:documentation> + </xs:annotation> + </xs:element> + <xs:element name="F60000246" type="xs:string"> + <xs:annotation> + <xs:documentation> + <name>Postleitzahl</name> + <definition>Es ist die Postleitzahl anzugeben.
 + 
 + Der Typ dieses Elements ist eine Einschränkung des Basistyps String.Latin. + </definition> + <bezug>XInneres.Meldeanschrift.postleitzahl Version 8</bezug> + </xs:documentation> + </xs:annotation> + </xs:element> + <xs:element name="F60000247" type="xs:string"> + <xs:annotation> + <xs:documentation> + <name>Ort</name> + <beschreibung>Kompatibilität zu EPA in TR XhD v 1.4 sollte Feldlänge min. 44. Laut PAuswV 2*25 = + 50 Zeichen. Laut Xinneres.Meldeanschrift.Wohnort Version 8 = 40 Zeichen. + Laut BSI TR-03123 kleiner gleich 105 Zeichen. + </beschreibung> + <definition>Enthält den Namen eines Ortes (Gemeinde, Ortschaft oder Stadt).</definition> + <bezug>§ 5 (2) Nr. 9 PAuswG vom 21.6.2019; Anhang 3 Abschnitt 1 (Wohnort) PAuswV vom 28.9.2017; + Tabelle 11 BSI TR-03123, Version 1.5.1; Xinneres.Meldeanschrift.Wohnort Version 8; + XOEV.Kernkomponente.Anschrift.ort vom 31.01.2020 + </bezug> + </xs:documentation> + </xs:annotation> + </xs:element> + <xs:element minOccurs="0" name="F60000248" type="xs:string"> + <xs:annotation> + <xs:documentation> + <name>Anschrift Zusatzangaben</name> + <definition>Es sind Zusatzangaben zur Anschrift anzugeben, z.B. Hinterhaus, Gartenhaus.
 + </definition> + <bezug>XInneres.Meldeanschrift.zusatzangaben Version 8</bezug> + </xs:documentation> + </xs:annotation> + </xs:element> + </xs:sequence> + </xs:complexType> + <xs:complexType name="G17007201"> + <xs:sequence> + <xs:element name="F60000228" type="xs:string"> + <xs:annotation> + <xs:documentation> + <name>Vornamen</name> + <beschreibung>Laut BSI TR-03123 soll Vorname <= 80 Zeichen betragen.
 + Laut PAuswV soll Vorname nicht mehr als 26 Zeichen bzw. 2*40 = 80 Zeichen betragen. + </beschreibung> + <definition>Plural zu Vorname</definition> + <bezug>§ 5 (2) Nr. 2 PAuswG vom 21.6.2019; Anhang 3 PAuswV vom 28.9.2017; 
 + Tabelle 9 BSI TR-03123 Version 1.5.1; XOEV.Kernkomponente.NameNatuerlichePerson.vorname vom + 31.08.2020 + </bezug> + </xs:documentation> + </xs:annotation> + </xs:element> + <xs:element name="F60000227" type="xs:string"> + <xs:annotation> + <xs:documentation> + <name>Familienname</name> + <beschreibung>Laut BSI TR-03123 soll die Gesamtlänge für Familienname, Titel und Geburtsname + nicht mehr als 120 Zeichen betragen. Laut PAuswV soll Name (Familienname und Geburtsname) + nicht mehr als 2*26 = 52 Zeichen bzw. 3*40 = 120 Zeichen betragen. + </beschreibung> + <definition>Familienname einer natürlichen Person bestehend aus Nachname, Zuname bzw. + Familienname. + </definition> + <bezug>§ 5 (2) Nr. 1 PAuswG vom 21.6.2019; Anhang 3 PAuswV vom 28.9.2017; Tabelle 9 BSI TR-03123 + Version 1.5.1; XOEV.Kernkomponente.NameNatuerlichePerson.familienname vom 31.01.2020 + </bezug> + </xs:documentation> + </xs:annotation> + </xs:element> + <xs:element minOccurs="0" name="F60000240" type="xs:string"> + <xs:annotation> + <xs:documentation> + <name>Telefon</name> + <beschreibung>Dieses Feld wurde angelehnt an ITU E.123. Eine Prüfung über ein Pattern erfolgt + nicht, um den Eingebenden nicht zu überfordern. + </beschreibung> + <definition>Telefonnummer</definition> + <bezug>ITU E.123</bezug> + </xs:documentation> + </xs:annotation> + </xs:element> + <xs:element minOccurs="0" name="F60000242" type="xs:string"> + <xs:annotation> + <xs:documentation> + <name>E-Mail</name> + <definition>Elektronische Adresse zum Senden und Empfangen von digitalen Nachrichten (E-Mails) + z.B. MaxMustermann@email.de + </definition> + <bezug>RFC 5322; RFC 5321</bezug> + </xs:documentation> + </xs:annotation> + </xs:element> + </xs:sequence> + </xs:complexType> + <xs:complexType name="G17005404"> + <xs:sequence> + <xs:element name="G17007202" type="xfd:G17007202"> + <xs:annotation> + <xs:documentation> + <name>Allgemeine Angaben zur Versammlung</name> + <bezug>Art. 8 GG ; § 11 VershFG SH</bezug> + </xs:documentation> + </xs:annotation> + </xs:element> + <xs:element name="G17007205" type="xfd:G17007205"> + <xs:annotation> + <xs:documentation> + <name>Weitere Angaben</name> + <definition>Angaben zur geplanten Durchführung der Versammlung.</definition> + <bezug>Art. 8 GG ; §§ 9, 11 VersFG SH</bezug> + </xs:documentation> + </xs:annotation> + </xs:element> + </xs:sequence> + </xs:complexType> + <xs:complexType name="G17007202"> + <xs:sequence> + <xs:element name="F17003373" type="xs:string"> + <xs:annotation> + <xs:documentation> + <name>Thema der Versammlung</name> + <bezug>Art. 8 GG; § 11 VershFG SG</bezug> + </xs:documentation> + </xs:annotation> + </xs:element> + <xs:element minOccurs="0" name="F17011810" type="xs:string"> + <xs:annotation> + <xs:documentation> + <name>Beschreibung der Versammlung</name> + <bezug>Art. 8 GG ; § 11 VershFG SH</bezug> + </xs:documentation> + </xs:annotation> + </xs:element> + <xs:element name="F17003377" type="xs:string"> + <xs:annotation> + <xs:documentation> + <name>Versammlungsort</name> + <bezug>Art. 8 GG; § 11 VershFG SG</bezug> + </xs:documentation> + </xs:annotation> + </xs:element> + <xs:element minOccurs="0" name="G17005405" type="xfd:G17005405"> + <xs:annotation> + <xs:documentation> + <name>Karte Versammlungsort</name> + <definition>Anlage eines Kartenausschnitts</definition> + <bezug>Art. 8 GG; § 11 VershFG SG</bezug> + </xs:documentation> + </xs:annotation> + </xs:element> + <xs:element name="G17005406" type="xfd:G17005406"> + <xs:annotation> + <xs:documentation> + <name>Zeitraum (Versammlungsanzeige)</name> + <definition>Gibt den Anfang und das Ende eines Zeitraums an.</definition> + <bezug>Art. 8 GG; § 11 VershFG SG</bezug> + </xs:documentation> + </xs:annotation> + </xs:element> + <xs:element minOccurs="0" name="F17011814" type="xs:string"> + <xs:annotation> + <xs:documentation> + <name>Grund für die verspätete Anmeldung</name> + <definition>Im Falle der nicht fristgemäßen Anmeldung der Versammlung - Optional Grund + ergänzen. + </definition> + <bezug>Art. 8 GG ; § 11 VershFG SH</bezug> + </xs:documentation> + </xs:annotation> + </xs:element> + <xs:element minOccurs="0" name="F17011815" type="xs:string"> + <xs:annotation> + <xs:documentation> + <name>Telefonnummer zur Rücksprache der verspäteten Anmeldung</name> + <bezug>Art. 8 GG ; § 11 VershFG SH iVm ITU E.123</bezug> + </xs:documentation> + </xs:annotation> + </xs:element> + </xs:sequence> + </xs:complexType> + <xs:complexType name="G17005405"> + <xs:sequence> + <xs:element maxOccurs="5" minOccurs="0" name="F60000296" type="xs:string"> + <xs:annotation> + <xs:documentation> + <name>Nachweis</name> + <definition>Nachweisdokument, um eine Information zu bestätigen, z.B. Sachkundenachweis. + </definition> + </xs:documentation> + </xs:annotation> + </xs:element> + </xs:sequence> + </xs:complexType> + <xs:complexType name="G17005406"> + <xs:sequence> + <xs:element name="F60000048" type="xs:date"> + <xs:annotation> + <xs:documentation> + <name>Anfang</name> + <definition>Beinhaltet das Datum des Anfangs eines Zeitraums.</definition> + <bezug>urn:xoev-de:kosit:xoev:kernkomponente:zeitraum vom 31.08.2020</bezug> + </xs:documentation> + </xs:annotation> + </xs:element> + <xs:element name="F17001348" type="xs:decimal"> + <xs:annotation> + <xs:documentation> + <name>Uhrzeit Start</name> + <bezug>div.</bezug> + </xs:documentation> + </xs:annotation> + </xs:element> + <xs:element name="F60000049" type="xs:date"> + <xs:annotation> + <xs:documentation> + <name>Ende</name> + <definition>Beinhaltet das Datum des Ende eines Zeitraums.</definition> + <bezug>urn:xoev-de:kosit:xoev:kernkomponente:zeitraum vom 31.08.2020</bezug> + </xs:documentation> + </xs:annotation> + </xs:element> + <xs:element name="F17001349" type="xs:decimal"> + <xs:annotation> + <xs:documentation> + <name>Uhrzeit Abschluss</name> + <bezug>div.</bezug> + </xs:documentation> + </xs:annotation> + </xs:element> + </xs:sequence> + </xs:complexType> + <xs:complexType name="G17007205"> + <xs:sequence> + <xs:element name="F17003379" type="xs:integer"> + <xs:annotation> + <xs:documentation> + <name>Anzahl der Teilnehmenden</name> + <bezug>Art. 8 GG; § 11 VershFG SH</bezug> + </xs:documentation> + </xs:annotation> + </xs:element> + <xs:element minOccurs="0" name="F17003380" type="xs:integer"> + <xs:annotation> + <xs:documentation> + <name>Anzahl eingeplanter Ordner:innen</name> + <definition>Empfehlung: 1 Ordner:in je 50 Teilnehmende</definition> + <bezug>Art. 8 GG; § 11 VershFG SG</bezug> + </xs:documentation> + </xs:annotation> + </xs:element> + <xs:element minOccurs="0" name="F17003382" type="xs:string"> + <xs:annotation> + <xs:documentation> + <name>Weitere teilnehmende Organisationen</name> + <bezug>Art. 8 GG; § 11 VershFG SG</bezug> + </xs:documentation> + </xs:annotation> + </xs:element> + <xs:element name="G17007234" type="xfd:G17007234"> + <xs:annotation> + <xs:documentation> + <name>Aufbauzeit</name> + <bezug>§§ 11,14 VersFG SH</bezug> + </xs:documentation> + </xs:annotation> + </xs:element> + <xs:element name="G17007235" type="xfd:G17007235"> + <xs:annotation> + <xs:documentation> + <name>Abbauzeit</name> + <bezug>§§ 11,14 VersFG SH</bezug> + </xs:documentation> + </xs:annotation> + </xs:element> + <xs:element minOccurs="0" name="F17003383" type="xs:string"> + <xs:annotation> + <xs:documentation> + <name>Demonstrationsmittel</name> + <bezug>Art. 8 GG; § 11 VershFG SG</bezug> + </xs:documentation> + </xs:annotation> + </xs:element> + <xs:element minOccurs="0" name="G17007207" type="xfd:G17007207"> + <xs:annotation> + <xs:documentation> + <name>Zusätzliche Informationen zu den geplanten Demonstrationsmitteln</name> + <definition>Optionale Schätzung der Anzahl der Fahnen und Transparente.</definition> + <bezug>Art. 8 GG ; §§ 9, 11 VershFG SH</bezug> + </xs:documentation> + </xs:annotation> + </xs:element> + <xs:element minOccurs="0" name="F17003384" type="xs:string"> + <xs:annotation> + <xs:documentation> + <name>Lautsprechereinsatz</name> + <bezug>Art. 8 GG ; § 11 VersFG SG</bezug> + </xs:documentation> + </xs:annotation> + </xs:element> + <xs:element minOccurs="0" name="G17007208" type="xfd:G17007208"> + <xs:annotation> + <xs:documentation> + <name>Zusätzliche Informationen zum geplanten Lautsprechereinsatz</name> + <definition>Angaben zum geplanten Einsatz von Lautsprechern und ggf. Transportfahrzeugen + (Musikanlagen, Megafone, PKW/LKW usw.) + </definition> + <bezug>Art. 8 GG ; § 11 VersFG SH</bezug> + </xs:documentation> + </xs:annotation> + </xs:element> + <xs:element maxOccurs="unbounded" minOccurs="0" name="G17007209" type="xfd:G17007209"> + <xs:annotation> + <xs:documentation> + <name>Geplante Bühnen</name> + <bezug>Art. 8 GG ; § 11 VersFG SH</bezug> + </xs:documentation> + </xs:annotation> + </xs:element> + <xs:element minOccurs="0" name="G17007210" type="xfd:G17007210"> + <xs:annotation> + <xs:documentation> + <name>Lagepläne / Skizzen der Aufbauten, Bilder / Informationen zu den Demonstrationsmitteln + oder sonstige Dokumente/Informationen hochladen + </name> + <bezug>Art. 8 GG ; §§ 9, 11 VersFG SH</bezug> + </xs:documentation> + </xs:annotation> + </xs:element> + </xs:sequence> + </xs:complexType> + <xs:complexType name="G17007234"> + <xs:sequence> + <xs:element name="F17011826" type="xs:string"> + <xs:annotation> + <xs:documentation> + <name>Beträgt die Aufbauzeit über 30 Minuten?</name> + <bezug>Art. 8 GG ; § 11 VersFG SH</bezug> + </xs:documentation> + </xs:annotation> + </xs:element> + <xs:element minOccurs="0" name="F17011853" type="xs:integer"> + <xs:annotation> + <xs:documentation> + <name>Auf-/Abbauzeit > 30 min</name> + <definition>Wenn die Auf- bzw. Abbauzeit mehr als 30 min beträgt in "F17011826 Beträgt die + Aufbauzeit über 30 Minuten?" bzw. in "F17011827 Beträgt die Abbauzeit über 30 Minuten?" = + Auswahl in C17001209 = 001 "Ja", wird "F17011853 Auf-/Abbauzeit > 30 min" zu einer + Pflichtangabe.
 + </definition> + <bezug>§§ 11,14 VersFG SH</bezug> + </xs:documentation> + </xs:annotation> + </xs:element> + </xs:sequence> + </xs:complexType> + <xs:complexType name="G17007235"> + <xs:sequence> + <xs:element name="F17011827" type="xs:string"> + <xs:annotation> + <xs:documentation> + <name>Beträgt die Abbauzeit über 30 Minuten?</name> + <bezug>Art. 8 GG ; § 11 VersFG SH</bezug> + </xs:documentation> + </xs:annotation> + </xs:element> + <xs:element minOccurs="0" name="F17011853" type="xs:integer"> + <xs:annotation> + <xs:documentation> + <name>Auf-/Abbauzeit > 30 min</name> + <definition>Wenn die Auf- bzw. Abbauzeit mehr als 30 min beträgt in "F17011826 Beträgt die + Aufbauzeit über 30 Minuten?" bzw. in "F17011827 Beträgt die Abbauzeit über 30 Minuten?" = + Auswahl in C17001209 = 001 "Ja", wird "F17011853 Auf-/Abbauzeit > 30 min" zu einer + Pflichtangabe.
 + </definition> + <bezug>§§ 11,14 VersFG SH</bezug> + </xs:documentation> + </xs:annotation> + </xs:element> + </xs:sequence> + </xs:complexType> + <xs:complexType name="G17007207"> + <xs:sequence> + <xs:element minOccurs="0" name="F17011818" type="xs:integer"> + <xs:annotation> + <xs:documentation> + <name>Anzahl Transparente</name> + <bezug>Art. 8 GG ; § 11 VersFG SH</bezug> + </xs:documentation> + </xs:annotation> + </xs:element> + <xs:element minOccurs="0" name="F17011819" type="xs:integer"> + <xs:annotation> + <xs:documentation> + <name>Anzahl Fahnen</name> + <bezug>Art. 8 GG ; § 11 VersFG SH</bezug> + </xs:documentation> + </xs:annotation> + </xs:element> + </xs:sequence> + </xs:complexType> + <xs:complexType name="G17007208"> + <xs:sequence> + <xs:element minOccurs="0" name="F17011820" type="xs:integer"> + <xs:annotation> + <xs:documentation> + <name>Anzahl Lautsprecher(anlagen)</name> + <bezug>Art. 8 GG ; § 11 VersFG SH</bezug> + </xs:documentation> + </xs:annotation> + </xs:element> + <xs:element minOccurs="0" name="F17011821" type="xs:integer"> + <xs:annotation> + <xs:documentation> + <name>Anzahl Megafone</name> + <bezug>Art. 8 GG ; § 11 VersFG SH</bezug> + </xs:documentation> + </xs:annotation> + </xs:element> + <xs:element minOccurs="0" name="F17011822" type="xs:integer"> + <xs:annotation> + <xs:documentation> + <name>Anzahl PKW</name> + <bezug>Art. 8 GG ; § 11 VersFG SH</bezug> + </xs:documentation> + </xs:annotation> + </xs:element> + <xs:element minOccurs="0" name="F17011824" type="xs:integer"> + <xs:annotation> + <xs:documentation> + <name>Anzahl LKW</name> + <bezug>Art. 8 GG ; § 11 VersFG SH</bezug> + </xs:documentation> + </xs:annotation> + </xs:element> + <xs:element minOccurs="0" name="F17011823" type="xs:decimal"> + <xs:annotation> + <xs:documentation> + <name>Gewicht LKW</name> + <bezug>Art. 8 GG ; § 11 VersFG SH</bezug> + </xs:documentation> + </xs:annotation> + </xs:element> + </xs:sequence> + </xs:complexType> + <xs:complexType name="G17007209"> + <xs:sequence> + <xs:element name="F17011825" type="xs:boolean"> + <xs:annotation> + <xs:documentation> + <name>Fester Bühnenaufbau?</name> + <definition>Wahrheitswert: Auswahl = "ja" entspricht "Fester Aufbau" - Auswahl ="nein" + entspricht "mobile Bühne" + </definition> + <bezug>Art. 8 GG ; § 11 VersFG SH</bezug> + </xs:documentation> + </xs:annotation> + </xs:element> + <xs:element name="F60000302" type="xs:decimal"> + <xs:annotation> + <xs:documentation> + <name>Länge in m</name> + </xs:documentation> + </xs:annotation> + </xs:element> + <xs:element name="F60000303" type="xs:decimal"> + <xs:annotation> + <xs:documentation> + <name>Breite in m</name> + </xs:documentation> + </xs:annotation> + </xs:element> + <xs:element name="F60000311" type="xs:decimal"> + <xs:annotation> + <xs:documentation> + <name>Gewicht in kg</name> + </xs:documentation> + </xs:annotation> + </xs:element> + </xs:sequence> + </xs:complexType> + <xs:complexType name="G17007210"> + <xs:sequence> + <xs:element maxOccurs="unbounded" minOccurs="0" name="F60000296" type="xs:string"> + <xs:annotation> + <xs:documentation> + <name>Nachweis</name> + <definition>Nachweisdokument, um eine Information zu bestätigen, z.B. Sachkundenachweis. + </definition> + </xs:documentation> + </xs:annotation> + </xs:element> + </xs:sequence> + </xs:complexType> + <xs:complexType name="G17005410"> + <xs:sequence> + <xs:element name="G17007211" type="xfd:G17007211"> + <xs:annotation> + <xs:documentation> + <name>Allgemeine Angaben zum Aufzug</name> + <bezug>Art. 8 GG ; § 11 VershFG SH</bezug> + </xs:documentation> + </xs:annotation> + </xs:element> + <xs:element minOccurs="0" name="F17011830" type="xs:string"> + <xs:annotation> + <xs:documentation> + <name>Art der Teilnahme</name> + <definition>Auswahl Art der Teilnahme</definition> + <bezug>Art. 8 GG ; § 11 VersFG SH</bezug> + </xs:documentation> + </xs:annotation> + </xs:element> + <xs:element name="G17005412" type="xfd:G17005412"> + <xs:annotation> + <xs:documentation> + <name>Anfangspunkt</name> + <bezug>Art. 8 GG ; § 11 VersFG SG</bezug> + </xs:documentation> + </xs:annotation> + </xs:element> + <xs:element name="G17005501" type="xfd:G17005501"> + <xs:annotation> + <xs:documentation> + <name>Streckenverlauf</name> + <definition>Angaben zum Streckenverlauf und ggf. Karte hinzufügen</definition> + <bezug>Art. 8 GG ; § 11 VersFG SG</bezug> + </xs:documentation> + </xs:annotation> + </xs:element> + <xs:element maxOccurs="20" minOccurs="0" name="G17005411" type="xfd:G17005411"> + <xs:annotation> + <xs:documentation> + <name>Zwischenkundgebung</name> + <definition>Angaben zu möglichen Zwischenkundgebungen</definition> + <bezug>Art. 8 GG; § 11 VershFG SG
 + </bezug> + </xs:documentation> + </xs:annotation> + </xs:element> + <xs:element name="F17009218" type="xs:boolean"> + <xs:annotation> + <xs:documentation> + <name>Anfangspunkt = Endpunkt der Versammlung</name> + <definition>Wenn die Versammlung am gleichen Ort beginnt an dem Sie auch endet</definition> + <bezug>Art. 8 GG;§ 11 VershFG SG
 + </bezug> + </xs:documentation> + </xs:annotation> + </xs:element> + <xs:element minOccurs="0" name="G17005413" type="xfd:G17005413"> + <xs:annotation> + <xs:documentation> + <name>Anschrift Inland Straßenanschrift (Ende)</name> + <bezug>Art. 8 GG; § 11 VershFG SG</bezug> + </xs:documentation> + </xs:annotation> + </xs:element> + <xs:element name="G17007205" type="xfd:G17007205"> + <xs:annotation> + <xs:documentation> + <name>Weitere Angaben</name> + <definition>Angaben zur geplanten Durchführung der Versammlung.</definition> + <bezug>Art. 8 GG ; §§ 9, 11 VersFG SH</bezug> + </xs:documentation> + </xs:annotation> + </xs:element> + </xs:sequence> + </xs:complexType> + <xs:complexType name="G17007211"> + <xs:sequence> + <xs:element name="F17011828" type="xs:string"> + <xs:annotation> + <xs:documentation> + <name>Thema des Aufzug</name> + <bezug>Art. 8 GG; § 11 VersFG SG</bezug> + </xs:documentation> + </xs:annotation> + </xs:element> + <xs:element minOccurs="0" name="F17011829" type="xs:string"> + <xs:annotation> + <xs:documentation> + <name>Beschreibung des Aufzug</name> + <bezug>Art. 8 GG ; § 11 VersFG SH</bezug> + </xs:documentation> + </xs:annotation> + </xs:element> + <xs:element name="G17005406" type="xfd:G17005406"> + <xs:annotation> + <xs:documentation> + <name>Zeitraum (Versammlungsanzeige)</name> + <definition>Gibt den Anfang und das Ende eines Zeitraums an.</definition> + <bezug>Art. 8 GG; § 11 VershFG SG</bezug> + </xs:documentation> + </xs:annotation> + </xs:element> + <xs:element minOccurs="0" name="F17011814" type="xs:string"> + <xs:annotation> + <xs:documentation> + <name>Grund für die verspätete Anmeldung</name> + <definition>Im Falle der nicht fristgemäßen Anmeldung der Versammlung - Optional Grund + ergänzen. + </definition> + <bezug>Art. 8 GG ; § 11 VershFG SH</bezug> + </xs:documentation> + </xs:annotation> + </xs:element> + <xs:element minOccurs="0" name="F17011815" type="xs:string"> + <xs:annotation> + <xs:documentation> + <name>Telefonnummer zur Rücksprache der verspäteten Anmeldung</name> + <bezug>Art. 8 GG ; § 11 VershFG SH iVm ITU E.123</bezug> + </xs:documentation> + </xs:annotation> + </xs:element> + </xs:sequence> + </xs:complexType> + <xs:complexType name="G17005412"> + <xs:sequence> + <xs:element name="G60000086" type="xfd:G60000086"> + <xs:annotation> + <xs:documentation> + <name>Anschrift Inland Straßenanschrift</name> + <definition>Angaben für die Adressierung im Inland, soweit es sich um die Anschrift eines + Gebäudes handelt. + </definition> + <bezug>urn:xoevde:xunternehmen:kerndatenobjekt:anschriftinlandstrassenanschrift</bezug> + </xs:documentation> + </xs:annotation> + </xs:element> + <xs:element minOccurs="0" name="G17005405" type="xfd:G17005405"> + <xs:annotation> + <xs:documentation> + <name>Karte Versammlungsort</name> + <definition>Anlage eines Kartenausschnitts</definition> + <bezug>Art. 8 GG; § 11 VershFG SG</bezug> + </xs:documentation> + </xs:annotation> + </xs:element> + </xs:sequence> + </xs:complexType> + <xs:complexType name="G17005501"> + <xs:sequence> + <xs:element name="F17009317" type="xs:string"> + <xs:annotation> + <xs:documentation> + <name>Beschreibung Streckenverlauf</name> + <definition>Freitextfeld zum Streckenverlauf.</definition> + <bezug>Art. 8 GG ; § 11 VersFG SG
 + </bezug> + </xs:documentation> + </xs:annotation> + </xs:element> + <xs:element minOccurs="0" name="G17007212" type="xfd:G17007212"> + <xs:annotation> + <xs:documentation> + <name>Karte Streckenverlauf</name> + <definition>Anlage eines Kartenausschnitts</definition> + <bezug>Art. 8 GG; § 11 VershFG SG</bezug> + </xs:documentation> + </xs:annotation> + </xs:element> + </xs:sequence> + </xs:complexType> + <xs:complexType name="G17007212"> + <xs:sequence> + <xs:element maxOccurs="5" minOccurs="0" name="F60000296" type="xs:string"> + <xs:annotation> + <xs:documentation> + <name>Nachweis</name> + <definition>Nachweisdokument, um eine Information zu bestätigen, z.B. Sachkundenachweis. + </definition> + </xs:documentation> + </xs:annotation> + </xs:element> + </xs:sequence> + </xs:complexType> + <xs:complexType name="G17005411"> + <xs:sequence> + <xs:element name="G17004014" type="xfd:G17004014"> + <xs:annotation> + <xs:documentation> + <name>Zeitraum (Versammlungsanzeige)</name> + <definition>Gibt den Anfang und das Ende eines Zeitraums an.</definition> + <bezug>Art. 8 GG; § 11 VershFG SG</bezug> + </xs:documentation> + </xs:annotation> + </xs:element> + <xs:element name="G60000086" type="xfd:G60000086"> + <xs:annotation> + <xs:documentation> + <name>Anschrift Inland Straßenanschrift</name> + <definition>Angaben für die Adressierung im Inland, soweit es sich um die Anschrift eines + Gebäudes handelt. + </definition> + <bezug>urn:xoevde:xunternehmen:kerndatenobjekt:anschriftinlandstrassenanschrift</bezug> + </xs:documentation> + </xs:annotation> + </xs:element> + <xs:element minOccurs="0" name="G17005405" type="xfd:G17005405"> + <xs:annotation> + <xs:documentation> + <name>Karte Versammlungsort</name> + <definition>Anlage eines Kartenausschnitts</definition> + <bezug>Art. 8 GG; § 11 VershFG SG</bezug> + </xs:documentation> + </xs:annotation> + </xs:element> + </xs:sequence> + </xs:complexType> + <xs:complexType name="G17004014"> + <xs:sequence> + <xs:element name="F60000048" type="xs:date"> + <xs:annotation> + <xs:documentation> + <name>Anfang</name> + <definition>Beinhaltet das Datum des Anfangs eines Zeitraums.</definition> + <bezug>urn:xoev-de:kosit:xoev:kernkomponente:zeitraum vom 31.08.2020</bezug> + </xs:documentation> + </xs:annotation> + </xs:element> + <xs:element name="F17001348" type="xs:decimal"> + <xs:annotation> + <xs:documentation> + <name>Uhrzeit Start</name> + <bezug>div.</bezug> + </xs:documentation> + </xs:annotation> + </xs:element> + <xs:element name="F60000049" type="xs:date"> + <xs:annotation> + <xs:documentation> + <name>Ende</name> + <definition>Beinhaltet das Datum des Ende eines Zeitraums.</definition> + <bezug>urn:xoev-de:kosit:xoev:kernkomponente:zeitraum vom 31.08.2020</bezug> + </xs:documentation> + </xs:annotation> + </xs:element> + <xs:element name="F17001349" type="xs:decimal"> + <xs:annotation> + <xs:documentation> + <name>Uhrzeit Abschluss</name> + <bezug>div.</bezug> + </xs:documentation> + </xs:annotation> + </xs:element> + </xs:sequence> + </xs:complexType> + <xs:complexType name="G17005413"> + <xs:sequence> + <xs:element name="F60000243" type="xs:string"> + <xs:annotation> + <xs:documentation> + <name>Straße</name> + <beschreibung>Kompatibilität zu EPA in TR XhD v 1.4 sollte Feldlänge min. 50. Bei XInneres 8 ist + die Feldlänge <= 55 Zeichen. + </beschreibung> + <bezug>XInneres.Meldeanschrift.strasse Version 8</bezug> + </xs:documentation> + </xs:annotation> + </xs:element> + <xs:element minOccurs="0" name="F60000244" type="xs:string"> + <xs:annotation> + <xs:documentation> + <name>Hausnummer</name> + <beschreibung>Die Modellierung aus XInneres wurde nicht 1:1 übernommen, um die Komplexität für + die Ausfüllenden nicht zu hoch zu setzen. Es wurde darauf verzichtet für das Ende von + Hausnummernbereichen eigene Felder zu modellieren. Daher ist die Feldlänge hier + heraufgesetzt und eine entsprechende Beschreibung wurde eingefügt. Die Feldlänge setzt sich + aus der maximalen Feldlänge zweier Hausnummern (jeweils 4), zweier Buchstaben (jeweils 1) + und eines Zeichen (-) zusammen. + </beschreibung> + <definition>Es sind die Ziffern und Buchstabeneiner Hausnummer anzugeben. Eine Hausnummer dient + der genauen Lokalisierung eines Grundstücks, Gebäudes oder Gebäudeteils (Eingang) in einer + Straße. Geben Sie Hausnummernbereiche immer nach folgendem Beispiel ohne Leerzeichen an: + 12a-14d + </definition> + <bezug>XInneres.Meldeanschrift.hausnummer Version 8</bezug> + </xs:documentation> + </xs:annotation> + </xs:element> + <xs:element name="F60000246" type="xs:string"> + <xs:annotation> + <xs:documentation> + <name>Postleitzahl</name> + <definition>Es ist die Postleitzahl anzugeben.
 + 
 + Der Typ dieses Elements ist eine Einschränkung des Basistyps String.Latin. + </definition> + <bezug>XInneres.Meldeanschrift.postleitzahl Version 8</bezug> + </xs:documentation> + </xs:annotation> + </xs:element> + <xs:element name="F60000247" type="xs:string"> + <xs:annotation> + <xs:documentation> + <name>Ort</name> + <beschreibung>Kompatibilität zu EPA in TR XhD v 1.4 sollte Feldlänge min. 44. Laut PAuswV 2*25 = + 50 Zeichen. Laut Xinneres.Meldeanschrift.Wohnort Version 8 = 40 Zeichen.
 + Laut BSI TR-03123 ≤ 105 Zeichen. + </beschreibung> + <definition>Enthält den Namen eines Ortes (Gemeinde, Ortschaft oder Stadt).</definition> + <bezug>§ 5 (2) Nr. 9 PAuswG vom 21.6.2019; Anhang 3 Abschnitt 1 (Wohnort) PAuswV vom 28.9.2017; + Tabelle 11 BSI TR-03123, Version 1.5.1; Xinneres.Meldeanschrift.Wohnort Version 8; + XOEV.Kernkomponente.Anschrift.ort vom 31.01.2020 + </bezug> + </xs:documentation> + </xs:annotation> + </xs:element> + <xs:element minOccurs="0" name="G17005405" type="xfd:G17005405"> + <xs:annotation> + <xs:documentation> + <name>Karte Versammlungsort</name> + <definition>Anlage eines Kartenausschnitts</definition> + <bezug>Art. 8 GG; § 11 VershFG SG</bezug> + </xs:documentation> + </xs:annotation> + </xs:element> + </xs:sequence> + </xs:complexType> +</xs:schema> \ No newline at end of file diff --git a/fim-adapter/src/test/java/de/ozgcloud/eingang/fim/AntragstellerMapperTest.java b/fim-adapter/src/test/java/de/ozgcloud/eingang/fim/AntragstellerMapperTest.java new file mode 100644 index 0000000000000000000000000000000000000000..f6daa78ea5d7a00b56f86ed99941c87e1e0d6cc7 --- /dev/null +++ b/fim-adapter/src/test/java/de/ozgcloud/eingang/fim/AntragstellerMapperTest.java @@ -0,0 +1,130 @@ +package de.ozgcloud.eingang.fim; + +import static org.assertj.core.api.Assertions.*; +import static org.mockito.ArgumentMatchers.*; +import static org.mockito.Mockito.*; + +import java.util.Collections; +import java.util.Map; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; +import org.mockito.InjectMocks; +import org.mockito.Spy; + +import de.ozgcloud.eingang.common.formdata.Antragsteller; +import de.ozgcloud.eingang.common.formdata.FormData; +import de.ozgcloud.eingang.common.formdata.FormDataTestFactory; + +class AntragstellerMapperTest { + + @Spy + @InjectMocks + private AntragstellerMapper mapper; + + @DisplayName("Parse formData") + @Nested + class TestParseFormData { + + private final FormData formData = FormDataTestFactory.createBuilder().antragsteller(null).build(); + + @DisplayName("on existing antragsteller") + @Nested + class TestOnExistingAntragsteller { + + private final Map<String, Object> antragstellerMap = AntragstellerTestFactory.createAntragstellerAsFimMap(); + private final Antragsteller antragsteller = AntragstellerTestFactory.create(); + + @BeforeEach + void mock() { + doReturn(antragstellerMap).when(mapper).getAntragsteller(any()); + doReturn(antragsteller).when(mapper).mapAntragsteller(any()); + } + + @Test + void shouldCallGetAntragsteller() { + mapper.parseFormData(formData); + + verify(mapper).getAntragsteller(FormDataTestFactory.FORM_DATA); + } + + @Test + void shouldCallMapAntragsteller() { + mapper.parseFormData(formData); + + verify(mapper).mapAntragsteller(antragstellerMap); + } + + @Test + void shouldReturnFormDataWithAntragsteller() { + var mappedFormData = mapper.parseFormData(formData); + + assertThat(mappedFormData.getAntragsteller()).isNotNull(); + } + } + + @DisplayName("on missing antragsteller") + @Nested + class TestOnMissingAntragsteller { + + @BeforeEach + void mock() { + doReturn(Collections.emptyMap()).when(mapper).getAntragsteller(any()); + } + + @Test + void shouldReturnNullAsAntragsteller() { + var mappedFormData = mapper.parseFormData(formData); + + assertThat(mappedFormData.getAntragsteller()).isNull(); + } + } + } + + @DisplayName("Get antragsteller") + @Nested + class TestGetAntragsteller { + + @Test + void shouldReturnMapIfAntragstellerExists() { + var antragstellerMap = AntragstellerTestFactory.createAntragstellerAsFimMap(); + var formDataMap = Map.<String, Object>of(AntragstellerMapper.ANTRAGSTELLER_KEY, Map.of(FimDataUtil.VALUE_KEY, antragstellerMap)); + + var antragsteller = mapper.getAntragsteller(formDataMap); + + assertThat(antragsteller).isNotEmpty().usingRecursiveComparison().isEqualTo(antragstellerMap); + } + + @Test + void shouldReturnEmptyMapIfAntragstellerIsMissing() { + var antragsteller = mapper.getAntragsteller(Collections.emptyMap()); + + assertThat(antragsteller).isNull(); + } + } + + @DisplayName("Map antragsteller") + @Nested + class TestMapAntragsteller { + + @Test + void shouldMap() { + var antragstellerMap = AntragstellerTestFactory.createAntragstellerAsFimMap(); + + var antragsteller = mapper.mapAntragsteller(antragstellerMap); + + assertThat(antragsteller).usingRecursiveComparison().isEqualTo(AntragstellerTestFactory.create()); + } + + @Test + void shouldMapEmpty() { + var formData = Collections.<String, Object>emptyMap(); + + var antragsteller = mapper.mapAntragsteller(formData); + + assertThat(antragsteller).usingRecursiveComparison().isEqualTo(Antragsteller.builder().build()); + } + } +} \ No newline at end of file diff --git a/fim-adapter/src/test/java/de/ozgcloud/eingang/fim/AntragstellerTestFactory.java b/fim-adapter/src/test/java/de/ozgcloud/eingang/fim/AntragstellerTestFactory.java new file mode 100644 index 0000000000000000000000000000000000000000..e72806960894dce1f415e28f1624369c96852c71 --- /dev/null +++ b/fim-adapter/src/test/java/de/ozgcloud/eingang/fim/AntragstellerTestFactory.java @@ -0,0 +1,55 @@ +package de.ozgcloud.eingang.fim; + +import java.util.HashMap; +import java.util.Map; + +import com.thedeanda.lorem.LoremIpsum; + +import de.ozgcloud.eingang.common.formdata.Antragsteller; +import lombok.AccessLevel; +import lombok.NoArgsConstructor; + +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public class AntragstellerTestFactory { + + public static final String VORNAME = LoremIpsum.getInstance().getWords(1); + public static final String NACHNAME = LoremIpsum.getInstance().getWords(1); + public static final String EMAIL = LoremIpsum.getInstance().getEmail(); + public static final String STRASSE = LoremIpsum.getInstance().getName(); + public static final String HAUSNUMMER = "4a"; + public static final String PLZ = LoremIpsum.getInstance().getZipCode(); + public static final String ORT = LoremIpsum.getInstance().getCity(); + + public static Antragsteller create() { + return createBuilder().build(); + } + + public static Antragsteller.AntragstellerBuilder createBuilder() { + return Antragsteller.builder() + .vorname(VORNAME) + .nachname(NACHNAME) + .email(EMAIL) + .strasse(STRASSE) + .hausnummer(HAUSNUMMER) + .plz(PLZ) + .ort(ORT); + } + + public static Map<String, Object> createAntragstellerAsFimMap() { + return Map.of( + AntragstellerMapper.VORNAME_KEY, Map.of(FimDataUtil.VALUE_KEY, VORNAME), + AntragstellerMapper.NACHNAME_KEY, Map.of(FimDataUtil.VALUE_KEY, NACHNAME), + AntragstellerMapper.EMAIL_KEY, Map.of(FimDataUtil.VALUE_KEY, EMAIL), + AntragstellerMapper.ANSCHRIFT_KEY, createAnschriftAsFimMap()); + } + + private static Map<String, Object> createAnschriftAsFimMap() { + var anschrift = new HashMap<String, Object>(); + anschrift.put(FimDataUtil.VALUE_KEY, Map.of( + AntragstellerMapper.STRASSE_KEY, Map.of(FimDataUtil.VALUE_KEY, STRASSE), + AntragstellerMapper.HAUSNUMMER_KEY, Map.of(FimDataUtil.VALUE_KEY, HAUSNUMMER), + AntragstellerMapper.PLZ_KEY, Map.of(FimDataUtil.VALUE_KEY, PLZ), + AntragstellerMapper.ORT_KEY, Map.of(FimDataUtil.VALUE_KEY, ORT))); + return anschrift; + } +} \ No newline at end of file diff --git a/fim-adapter/src/test/java/de/ozgcloud/eingang/fim/FimBasedAdapterITCase.java b/fim-adapter/src/test/java/de/ozgcloud/eingang/fim/FimBasedAdapterITCase.java new file mode 100644 index 0000000000000000000000000000000000000000..e32906bc408d40d53b0fc8969f6aa0fa5fd63bf3 --- /dev/null +++ b/fim-adapter/src/test/java/de/ozgcloud/eingang/fim/FimBasedAdapterITCase.java @@ -0,0 +1,176 @@ +package de.ozgcloud.eingang.fim; + +import static org.assertj.core.api.Assertions.*; + +import java.io.File; +import java.util.List; +import java.util.Map; +import java.util.Optional; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.autoconfigure.ImportAutoConfiguration; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.ActiveProfiles; + +import de.ozgcloud.common.test.ITCase; +import de.ozgcloud.eingang.common.formdata.Antragsteller; +import de.ozgcloud.eingang.common.formdata.FormData; +import de.ozgcloud.eingang.common.formdata.FormData.FormDataControl; +import de.ozgcloud.eingang.common.formdata.FormData.Representations; +import de.ozgcloud.eingang.common.formdata.FormHeader; +import de.ozgcloud.eingang.common.formdata.IncomingFile; +import de.ozgcloud.eingang.common.formdata.IncomingFileTestFactory; +import lombok.SneakyThrows; + +@ITCase +@ActiveProfiles({ "itcase", "test" }) +@ImportAutoConfiguration +@SpringBootTest(classes = FimTestConfig.class) +class FimBasedAdapterITCase { + + @Autowired // NOSONAR + private FimBasedAdapter fimBasedAdapter; + + @Nested + class TestFallback { + + @Test + void shouldWithFallbackUnknownScheme() { + var incomingFile = IncomingFile.builder().name("src/test/resources/test3/Antrag.xml") + .file(new File("src/test/resources/test3/Antrag.xml")) + .build(); + var incomingFile2 = IncomingFile.builder().name("src/test/resources/test3/fim_xtaMetadata.xml").build(); + var initialFormData = FormData.builder() + .header(FormHeader.builder().channel("XTA").formEngineName("FIM").build()) + .representations(List.of(incomingFile, incomingFile2)).build(); + + var formData = fimBasedAdapter.parseFormData(initialFormData); + + assertThat(formData).isNotNull(); + assertThat(formData.getFormData()).isEqualTo(getParsedDocumentMap()); + } + + private Map<String, Object> getParsedDocumentMap() { + return Map.of( + "G17003529", Map.of( + "label", "G17003529", + "value", Map.of( + "G05001479", Map.of( + "label", "G05001479", + "value", Map.of( + "G05001480", Map.of( + "label", "G05001480", + "value", Map.of( + "F05002750", + Map.of("label", "F05002750", "value", "d447e43a-5723-4821-a170-cb44d2dbf143"), + "F05002751", Map.of("label", "F05002751", "value", "2022-08-15T09:30:47"), + "F05002752", + Map.of("label", "F05002752", "value", "fim.S17000652.17000652001004"), + "F05002753", + Map.of("label", "F05002753", "value", "urn:fim:Versammlungsanzeige:1.4"))), + "G05001481", Map.of( + "label", "G05001481", + "value", Map.of( + "F05002754", Map.of("label", "F05002754", "value", "Celle"), + "F05002755", Map.of("label", "F05002755", "value", "vbe:010550120100"), + "F05002756", Map.of("label", "F05002756", "value", "Versammlungsbehörde"))), + "G05001482", Map.of( + "label", "G05001482", + "value", Map.of( + "F05002754", + Map.of("label", "F05002754", "value", + "OSI-Onlinedienst Niedersachsen Versammlungsanzeige"), + "F05002755", Map.of("label", "F05002755", "value", "vbe:010550120100"), + "F05002756", + Map.of("label", "F05002756", "value", "Engagement- und Hobbyportal"))))), + "F17005454", Map.of("label", "F17005454", "value", "true"), + "F17005455", Map.of("label", "F17005455", "value", "true"), + "F17005533", Map.of("label", "F17005533", "value", "String"))), + "F17009191", Map.of("label", "F17009191", "value", "true"), + "F17003371", Map.of("label", "F17003371", "value", "String")); + } + } + + @DisplayName("Parse formData") + @Nested + class TestParseFormData { + + private final String fileName = "antrag.xml"; + private final FormData emptyFormData = FormData.builder() + .control(FormDataControl.builder() + .representations(Optional.of(Representations.builder() + .primaryFormDataRepresentation(fileName) + .build())) + .build()) + .representation(IncomingFile.builder() + .name(fileName) + .file(new File("src/test/resources/" + fileName)) + .build()) + .build(); + + @Test + void shouldHaveHeaderFormName() { + var formData = fimBasedAdapter.parseFormData(emptyFormData); + + assertThat(formData).isNotNull(); + assertThat(formData.getHeader().getFormName()).isEqualTo("urn:fim:Versammlungsanzeige:1.4"); + } + + @Test + void shouldHaveAntragsteller() { + var formData = fimBasedAdapter.parseFormData(emptyFormData); + + assertThat(formData).isNotNull(); + assertThat(formData.getAntragsteller()).usingRecursiveComparison().isEqualTo(createExpectedAntragsteller()); + } + + private Antragsteller createExpectedAntragsteller() { + return Antragsteller.builder() + .vorname("Jörg").nachname("Smith") + .email("example@email.de") + .strasse("Muster") + .hausnummer("1") + .plz("12345") + .ort("Muster") + .build(); + } + } + + @DisplayName("Process data") + @Nested + class TestDoParse { + + @SneakyThrows + @Test + void shouldTransformSimpleDocument() { + var file = IncomingFileTestFactory.createBuilder().file(new File("src/test/resources/test2.xml")).build(); + + var formData = fimBasedAdapter.doParse(file); + + assertThat(formData).isEqualTo(FimDocumentTestHelper.getTest2AsMap()); + } + + @SneakyThrows + @Test + void shouldTransformSimpleDocumentWithoutNamespace() { + var file = IncomingFileTestFactory.createBuilder().file(new File("src/test/resources/test3.xml")).build(); + + var formData = fimBasedAdapter.doParse(file); + + assertThat(formData).isEqualTo(FimDocumentTestHelper.getTest3AsMap()); + } + + @SneakyThrows + @Test + void shouldTransformDocument() { + var file = IncomingFileTestFactory.createBuilder().file(new File("src/test/resources/S17000652V1.4_test01.xml")).build(); + + var formData = fimBasedAdapter.doParse(file); + + assertThat(formData).isNotEmpty().isEqualTo(FimDocumentTestHelper.getVersammlungsAnzeigeAsMap()); + } + } +} \ No newline at end of file diff --git a/fim-adapter/src/test/java/de/ozgcloud/eingang/fim/FimBasedAdapterTest.java b/fim-adapter/src/test/java/de/ozgcloud/eingang/fim/FimBasedAdapterTest.java index 43871ee93994b841dff00114aba3d950dd569fff..21965af09897d30280c3389b251f8b965264b7b2 100644 --- a/fim-adapter/src/test/java/de/ozgcloud/eingang/fim/FimBasedAdapterTest.java +++ b/fim-adapter/src/test/java/de/ozgcloud/eingang/fim/FimBasedAdapterTest.java @@ -24,46 +24,293 @@ package de.ozgcloud.eingang.fim; import static org.assertj.core.api.Assertions.*; +import static org.mockito.ArgumentMatchers.*; +import static org.mockito.Mockito.*; +import java.io.InputStream; +import java.util.Collections; +import java.util.List; +import java.util.Map; import java.util.Optional; +import org.junit.jupiter.api.AfterEach; +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.MockedStatic; +import org.mockito.Spy; +import org.w3c.dom.Document; -import de.ozgcloud.eingang.common.formdata.FormData.Representations; -import de.ozgcloud.eingang.common.formdata.FormDataControlTestFactory; +import de.ozgcloud.common.test.ReflectionTestUtils; +import de.ozgcloud.eingang.common.formdata.FormData; +import de.ozgcloud.eingang.common.formdata.FormDataTestFactory; +import de.ozgcloud.eingang.common.formdata.FormHeaderTestFactory; +import de.ozgcloud.eingang.common.formdata.IncomingFile; +import de.ozgcloud.eingang.common.formdata.IncomingFileTestFactory; +import de.ozgcloud.eingang.fim.FimDocumentHelper.FimDocumentProcessor; +import de.ozgcloud.eingang.fim.common.xml.DocumentHelper; class FimBasedAdapterTest { + @Spy @InjectMocks private FimBasedAdapter adapter; + @Mock + private FimService service; + @DisplayName("Is responsible") @Nested - class TestGetEntryPoint { + class TestIsResponsible { @Test - void shouldReturnPrimaryRepresentation() { - var result = adapter.getEntryPoint(FormDataControlTestFactory.create()); + void shouldBeTrueOnFimFormEngine() { + var formData = FormDataTestFactory.createBuilder() + .header(FormHeaderTestFactory.createBuilder().formEngineName(FimBasedAdapter.FIM_FORM_ENGINE_NAME).build()).build(); - assertThat(result).isEqualTo(FormDataControlTestFactory.PRIMARY_FORM_DATA_REPRESENTATION); + var isResponsible = adapter.isResponsible(formData); + + assertThat(isResponsible).isTrue(); + } + } + + @DisplayName("Parse formData") + @Nested + class TestParseFormData { + + private final FormData formData = FormDataTestFactory.create(); + private final FormData enrichedFormData = FormDataTestFactory.create(); + private final FormData processedFormData = FormDataTestFactory.create(); + + @Mock + private FimEngineBasedMapper mapper; + + @BeforeEach + void initMocks() { + ReflectionTestUtils.setField(adapter, "mappers", List.of(mapper)); + + doReturn(enrichedFormData).when(adapter).addFormDataDataMap(any()); + doReturn(processedFormData).when(mapper).parseFormData(any()); } @Test - void shouldReturnDefaultOnMissingRepresentations() { - var result = adapter.getEntryPoint(FormDataControlTestFactory.createBuilder().representations(Optional.empty()).build()); + void shouldCallAddFormDataDataMap() { + adapter.parseFormData(formData); - assertThat(result).isEqualTo(FimBasedAdapter.DEFAULT_FORMDATA_REPRESENTATION_NAME); + verify(adapter).addFormDataDataMap(formData); } @Test - void shouldReturnDefaultOnMissingPrimary() { - var control = FormDataControlTestFactory.createBuilder().representations(Optional.of(Representations.builder().build())).build(); + void shouldCallMapper() { + adapter.parseFormData(formData); + + verify(mapper).parseFormData(enrichedFormData); + } - var result = adapter.getEntryPoint(control); + @Test + void shouldReturnProcessedData() { + var parsedFormData = adapter.parseFormData(formData); - assertThat(result).isEqualTo(FimBasedAdapter.DEFAULT_FORMDATA_REPRESENTATION_NAME); + assertThat(parsedFormData).isEqualTo(processedFormData); } } + @DisplayName("Add formData dataMap") + @Nested + class TestAddFormDataDataMap { + + private final FormData formData = FormDataTestFactory.createBuilder().formData(null).build(); + private final Map<String, Object> parsedFormDataDataMap = Collections.emptyMap(); + + @BeforeEach + void initMocks() { + doReturn(parsedFormDataDataMap).when(adapter).parseRequestData(any()); + } + + @Test + void shouldCallParseRequestData() { + adapter.addFormDataDataMap(formData); + + verify(adapter).parseRequestData(formData); + } + + @Test + void shouldHaveAddFormData() { + var enrichedFormData = adapter.addFormDataDataMap(formData); + + assertThat(enrichedFormData.getFormData()).isEqualTo(parsedFormDataDataMap); + } + } + + @DisplayName("Parse requestData") + @Nested + class TestParseRequestData { + + private final FormData formData = FormDataTestFactory.create(); + + @DisplayName("on existing primary representation") + @Nested + class TestOnExistingPrimaryRepresentation { + + private final IncomingFile representation = IncomingFileTestFactory.create(); + private final Map<String, Object> parsedData = Collections.emptyMap(); + + @BeforeEach + void initMocks() { + when(service.findPrimaryRepresentation(any())).thenReturn(Optional.of(representation)); + doReturn(parsedData).when(adapter).doParse(any()); + } + + @Test + void shouldCallServiceToFindPrimaryRepresentation() { + adapter.parseRequestData(formData); + + verify(service).findPrimaryRepresentation(formData); + } + + @Test + void shouldCallDoParse() { + adapter.parseRequestData(formData); + + verify(adapter).doParse(representation); + } + + @Test + void shouldReturnParsedData() { + var parsedRequestData = adapter.parseRequestData(formData); + + assertThat(parsedRequestData).isEqualTo(parsedData); + } + } + + @Test + void shouldReturnEmptyMapOnMissingPrimaryRepresentation() { + when(service.findPrimaryRepresentation(any())).thenReturn(Optional.empty()); + + var parsedRequestData = adapter.parseRequestData(formData); + + assertThat(parsedRequestData).isEmpty(); + } + } + + @DisplayName("Do parse") + @Nested + class TestDoParse { + + @Mock + private IncomingFile file; + + private final InputStream inputStream = InputStream.nullInputStream(); + + @BeforeEach + void initMocks() { + when(file.getContentStream()).thenReturn(inputStream); + } + + @Test + void shouldCallDocumentHelperParse() { + try (var helper = mockStatic(DocumentHelper.class)) { + adapter.doParse(file); + + helper.verify(() -> DocumentHelper.parse(inputStream)); + } + } + + @Test + void shouldCallProcessData() { + try (var helper = mockStatic(DocumentHelper.class)) { + var parsedContent = mock(Document.class); + helper.when(() -> DocumentHelper.parse(any(InputStream.class))).thenReturn(parsedContent); + + adapter.doParse(file); + + verify(adapter).processData(parsedContent); + } + } + + @Test + void shouldReturnProcessedContent() { + try (var helper = mockStatic(DocumentHelper.class)) { + var parsedContent = mock(Document.class); + helper.when(() -> DocumentHelper.parse(any(InputStream.class))).thenReturn(parsedContent); + var processedMap = Collections.emptyMap(); + doReturn(processedMap).when(adapter).processData(any()); + + var parsedData = adapter.doParse(file); + + assertThat(parsedData).isEqualTo(processedMap); + } + } + + @Test + void shouldReturnEmptyMapOnException() { + try (var helper = mockStatic(DocumentHelper.class)) { + helper.when(() -> DocumentHelper.parse(any(InputStream.class))).thenThrow(new RuntimeException()); + + var parsedData = adapter.doParse(file); + + assertThat(parsedData).isEmpty(); + } + } + } + + @DisplayName("Process data") + @Nested + class TestProcessData { + + @Mock + private Document content; + @Mock + private FimScheme scheme; + + @Mock + private FimDocumentProcessor processor; + + private MockedStatic<FimDocumentHelper> helper; + private final Map<String, Object> dataMap = Collections.<String, Object>emptyMap(); + + @BeforeEach + void initMocks() { + helper = mockStatic(FimDocumentHelper.class); + helper.when(() -> FimDocumentHelper.createProcessor(any(), any())).thenReturn(processor); + + when(processor.process()).thenReturn(dataMap); + when(service.getScheme(any())).thenReturn(scheme); + } + + @AfterEach + void tearDown() { + helper.close(); + } + + @Test + void shouldCallServiceToGetScheme() { + adapter.processData(content); + + verify(service).getScheme(content); + } + + @Test + void shouldCreateFimDocumentHelperProcessor() { + adapter.processData(content); + + helper.verify(() -> FimDocumentHelper.createProcessor(content, scheme)); + } + + @Test + void shouldProcess() { + adapter.processData(content); + + verify(processor).process(); + } + + @Test + void shouldReturnProcessedData() { + var processedData = adapter.processData(content); + + assertThat(processedData).isEqualTo(dataMap); + } + } } diff --git a/fim-adapter/src/test/java/de/ozgcloud/eingang/fim/FimDataUtilTest.java b/fim-adapter/src/test/java/de/ozgcloud/eingang/fim/FimDataUtilTest.java new file mode 100644 index 0000000000000000000000000000000000000000..cb48785bcad73409f81fb3606a8f4e260b745445 --- /dev/null +++ b/fim-adapter/src/test/java/de/ozgcloud/eingang/fim/FimDataUtilTest.java @@ -0,0 +1,45 @@ +package de.ozgcloud.eingang.fim; + +import static org.assertj.core.api.Assertions.*; + +import java.util.Collections; +import java.util.Map; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; + +class FimDataUtilTest { + + @DisplayName("Get value as key") + @Nested + class TestGetValueAsKey { + + private final String fieldKey = "fieldKey"; + + private final Map<String, Object> valueDataMap = Collections.singletonMap("valueDataKey", "valueDataValue"); + private final Map<String, Object> valueMap = Collections.singletonMap(FimDataUtil.VALUE_KEY, valueDataMap); + private final Map<String, Object> fieldMap = Collections.singletonMap(fieldKey, valueMap); + + @Test + void shouldReturNullOnNullMap() { + var map = FimDataUtil.getValueMapByKey(null, fieldKey); + + assertThat(map).isNull(); + } + + @Test + void shouldReturnNullOnNullKeyValue() { + var map = FimDataUtil.getValueMapByKey(fieldMap, null); + + assertThat(map).isNull(); + } + + @Test + void shouldReturnValueMapEntry() { + var map = FimDataUtil.getValueMapByKey(fieldMap, fieldKey); + + assertThat(map).isEqualTo(valueDataMap); + } + } +} \ No newline at end of file diff --git a/fim-adapter/src/test/java/de/ozgcloud/eingang/fim/FimDocumentTestHelper.java b/fim-adapter/src/test/java/de/ozgcloud/eingang/fim/FimDocumentTestHelper.java new file mode 100644 index 0000000000000000000000000000000000000000..610263cc895893fd2abe162e469b405df679b7da --- /dev/null +++ b/fim-adapter/src/test/java/de/ozgcloud/eingang/fim/FimDocumentTestHelper.java @@ -0,0 +1,95 @@ +package de.ozgcloud.eingang.fim; + +import java.io.File; +import java.util.Map; + +import javax.xml.parsers.DocumentBuilderFactory; + +import org.w3c.dom.Document; + +import lombok.SneakyThrows; + +public class FimDocumentTestHelper { + + private static final String RESOURCE_PATH = "src/test/resources/"; + + public static Document getTest1Document() { + return loadDocument("test1.xml"); + } + + public static Document getTest2Document() { + return loadDocument("test2.xml"); + } + + public static Map<String, Object> getTest2AsMap() { + return Map.of( + "fim.S1235", Map.of("label", "Testkey", "value", "Testvalue"), + "fim.S1236", Map.of("label", "fim.S1236", "value", "Testvalue 2")); + } + + public static Document getTest3Document() { + return loadDocument("test3.xml"); + } + + public static Map<String, Object> getTest3AsMap() { + return Map.of( + "fim.S1235", Map.of("label", "Testkey", "value", "Testvalue"), + "fim.S1236", Map.of("label", "fim.S1236", "value", "Testvalue 2")); + } + + public static Document getVersammlungsAnzeigeDocument() { + return loadDocument("S17000652V1.4_test01.xml"); + } + + public static Map<String, Object> getVersammlungsAnzeigeAsMap() { + return Map.of( + "G17003529", Map.of( + "label", "EfA|SH Standard", + "value", Map.of( + "G05001479", Map.of( + "label", "nachrichtenkopf", + "value", Map.of( + "G05001480", Map.of( + "label", "identifikation.nachricht", + "value", Map.of( + "F05002750", + Map.of("label", "nachrichtenUUID", "value", "d447e43a-5723-4821-a170-cb44d2dbf143"), + "F05002751", + Map.of("label", "erstellungszeitpunkt", "value", "2022-08-15T09:30:47"), + "F05002752", + Map.of("label", "nachrichtentyp", "value", "fim.S17000652.17000652001004"), + "F05002753", + Map.of("label", "dienstname", "value", "urn:fim:Versammlungsanzeige:1.4"))), + "G05001481", Map.of( + "label", "Leser", + "value", Map.of( + "F05002754", Map.of("label", "Organisationsname", "value", "Celle"), + "F05002755", + Map.of("label", "Organisationsschlüssel", "value", "vbe:010550120100"), + "F05002756", Map.of("label", "Kategorie", "value", "Versammlungsbehörde"))), + "G05001482", Map.of( + "label", "Autor", + "value", Map.of( + "F05002754", + Map.of("label", "Organisationsname", "value", + "OSI-Onlinedienst Niedersachsen Versammlungsanzeige"), + "F05002755", + Map.of("label", "Organisationsschlüssel", "value", "vbe:010550120100"), + "F05002756", + Map.of("label", "Kategorie", "value", "Engagement- und Hobbyportal"))))), + "F17005454", Map.of("label", "Datenschutzhinweis DSGVO", "value", "true"), + "F17005455", Map.of("label", "Zustimmung zu einem digitalen Bescheid", "value", "true"), + "F17005533", Map.of("label", "UUID", "value", "String"))), + "F17009191", Map.of("label", "Anzeige durch Person", "value", "true"), + "F17003371", Map.of("label", "Anzeigenart", "value", "String")); + } + + public static Document getAntragDocument() { + return loadDocument("antrag.xml"); + } + + @SneakyThrows + private static Document loadDocument(String fileName) { + return DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(new File(RESOURCE_PATH + fileName)); + } +} \ No newline at end of file diff --git a/fim-adapter/src/test/java/de/ozgcloud/eingang/fim/FimSchemeHelperTest.java b/fim-adapter/src/test/java/de/ozgcloud/eingang/fim/FimSchemeHelperTest.java new file mode 100644 index 0000000000000000000000000000000000000000..7553fefb39eecae195f94a9fa79706efad3d5d52 --- /dev/null +++ b/fim-adapter/src/test/java/de/ozgcloud/eingang/fim/FimSchemeHelperTest.java @@ -0,0 +1,145 @@ +package de.ozgcloud.eingang.fim; + +import static org.assertj.core.api.Assertions.*; +import static org.mockito.ArgumentMatchers.*; +import static org.mockito.Mockito.*; + +import java.util.Collections; +import java.util.List; + +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.springframework.core.io.ResourceLoader; + +import de.ozgcloud.common.test.ReflectionTestUtils; + +class FimSchemeHelperTest { + + @InjectMocks + private FimSchemeHelper helper; + @Mock + private FimProperties fimProperties; + @Mock + private ResourceLoader resourceLoader; + + @DisplayName("Init") + @Nested + class TestInit { + + @BeforeEach + void initMocks() { + setFimSchemeAdapter(Collections.emptyList()); + } + + @DisplayName("scheme adapter catalogue") + @Nested + class TestInitSchemeAdapterCatalogue { + + @Mock + private FimSchemeAdapter adapter; + + @Test + void shouldInitByAdapter() { + setFimSchemeAdapter(List.of(adapter)); + + helper.init(); + + assertThat(getSchemeAdapterCatalogue()).isNotNull().hasSize(1); + } + + @Test + void shouldInit() { + helper.init(); + + assertThat(getSchemeAdapterCatalogue()).isNotNull().isEmpty(); + } + + private FimSchemeAdapterCatalogue getSchemeAdapterCatalogue() { + return ReflectionTestUtils.getField(helper, "schemeAdapterCatalogue", FimSchemeAdapterCatalogue.class); + } + } + + private void setFimSchemeAdapter(List<FimSchemeAdapter> adapterList) { + ReflectionTestUtils.setField(helper, "fimSchemeAdapters", adapterList); + } + + @Test + void shouldInitSchemeCatalogue() { + helper.init(); + + assertThat(getSchemeCatalogue()).isNotNull(); + } + + private FimSchemeCatalogue getSchemeCatalogue() { + return ReflectionTestUtils.getField(helper, "schemeCatalogue", FimSchemeCatalogue.class); + } + } + + @DisplayName("Get scheme") + @Nested + class TestGetScheme { + + @Mock + private FimSchemeCatalogue schemeCatalogue; + @Mock + private FimScheme fimScheme; + + private String identifier = "idenditifierName"; + + @BeforeEach + void mock() { + ReflectionTestUtils.setField(helper, "schemeCatalogue", schemeCatalogue); + when(schemeCatalogue.get(any())).thenReturn(fimScheme); + } + + @Test + void shouldCallSchemeCatalogue() { + helper.getScheme(identifier); + + verify(schemeCatalogue).get(FimSchemeIdentifier.fromString(identifier)); + } + + @Test + void shouldReturnScheme() { + var scheme = helper.getScheme(identifier); + + assertThat(scheme).isEqualTo(fimScheme); + } + } + + @DisplayName("Get default scheme") + @Nested + class TestGetDefaultScheme { + + @Mock + private FimSchemeCatalogue schemeCatalogue; + @Mock + private FimSchemeIdentifier identifier; + @Mock + private FimScheme fimScheme; + + @BeforeEach + void mock() { + ReflectionTestUtils.setField(helper, "schemeCatalogue", schemeCatalogue); + when(schemeCatalogue.get(any())).thenReturn(fimScheme); + } + + @Test + void shouldCallSchemeCatalogue() { + helper.getDefaultScheme(); + + verify(schemeCatalogue).get(FimSchemeIdentifier.fromString(UnknownSchemeAdapter.UNKNOWN_SCHEME_NAME)); + } + + @Test + void shouldReturnScheme() { + var scheme = helper.getDefaultScheme(); + + assertThat(scheme).isEqualTo(fimScheme); + } + } +} \ No newline at end of file diff --git a/fim-adapter/src/test/java/de/ozgcloud/eingang/fim/FimServiceITCase.java b/fim-adapter/src/test/java/de/ozgcloud/eingang/fim/FimServiceITCase.java deleted file mode 100644 index 299c45829efa33493e0a37deab4cddcdf5acf648..0000000000000000000000000000000000000000 --- a/fim-adapter/src/test/java/de/ozgcloud/eingang/fim/FimServiceITCase.java +++ /dev/null @@ -1,222 +0,0 @@ -/* - * Copyright (C) 2024 Das Land Schleswig-Holstein vertreten durch den - * Ministerpräsidenten des Landes Schleswig-Holstein - * Staatskanzlei - * Abteilung Digitalisierung und zentrales IT-Management der Landesregierung - * - * Lizenziert unter der EUPL, Version 1.2 oder - sobald - * diese von der Europäischen Kommission genehmigt wurden - - * Folgeversionen der EUPL ("Lizenz"); - * Sie dürfen dieses Werk ausschließlich gemäß - * dieser Lizenz nutzen. - * Eine Kopie der Lizenz finden Sie hier: - * - * https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 - * - * Sofern nicht durch anwendbare Rechtsvorschriften - * gefordert oder in schriftlicher Form vereinbart, wird - * die unter der Lizenz verbreitete Software "so wie sie - * ist", OHNE JEGLICHE GEWÄHRLEISTUNG ODER BEDINGUNGEN - - * ausdrücklich oder stillschweigend - verbreitet. - * Die sprachspezifischen Genehmigungen und Beschränkungen - * unter der Lizenz sind dem Lizenztext zu entnehmen. - */ -package de.ozgcloud.eingang.fim; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.AssertionsForClassTypes.assertThatThrownBy; - -import java.io.File; -import java.io.IOException; -import java.util.List; -import java.util.Map; - -import javax.xml.parsers.DocumentBuilder; -import javax.xml.parsers.DocumentBuilderFactory; -import javax.xml.parsers.ParserConfigurationException; - -import org.junit.jupiter.api.Test; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.autoconfigure.ImportAutoConfiguration; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.test.context.ActiveProfiles; -import org.w3c.dom.Document; -import org.xml.sax.SAXException; - -import de.ozgcloud.common.test.ITCase; -import de.ozgcloud.eingang.common.formdata.FormData; -import de.ozgcloud.eingang.common.formdata.FormDataTestFactory; -import de.ozgcloud.eingang.common.formdata.FormHeader; -import de.ozgcloud.eingang.common.formdata.IncomingFile; - -@ITCase -@ActiveProfiles({ "itcase", "test" }) -@ImportAutoConfiguration -@SpringBootTest(classes = FimTestConfig.class) -public class FimServiceITCase { - - @Autowired - private FimService fimService; - - @Autowired - private FimBasedAdapter fimBasedAdapter; - - @Test - void shouldFailOnEmptyScheme() { - assertThatThrownBy(() -> { - final Document document = loadDocument("src/test/resources/test1.xml"); - fimService.transformDocument(document, FormData.builder().build()); - }).isInstanceOf(FimException.class).hasMessage("XML Document does not provide a scheme"); - } - - @Test - void shouldNoFindInvalidScheme() { - final FimScheme scheme = fimService.getSchemeForIdentifier("test"); - - assertThat(FimSchemeIdentifier.fromString("unknown")).isEqualTo(scheme.getIdentifier()); - } - - @Test - void shouldFindVersammlungsScheme() { - final FimScheme scheme = fimService.getSchemeForIdentifier("urn:xoev-de:xfall:standard:fim-s17000652_1.4"); - assertThat(scheme).isNotNull(); - } - - @Test - void shouldFindTest2Scheme() { - final FimScheme scheme = fimService.getSchemeForIdentifier("test2"); - assertThat(scheme).isNotNull(); - } - - @Test - void shouldTransformSimpleDocument() throws ParserConfigurationException, IOException, SAXException { - final Document document = loadDocument("src/test/resources/test2.xml"); - final FormData formData = fimService.transformDocument(document, FormData.builder().build()); - - final Map<String, Object> expected = Map.of( - "xs:fim.S1235", Map.of("label", "Testkey", "value", "Testvalue"), - "xs:fim.S1236", Map.of("label", "xs:fim.S1236", "value", "Testvalue 2")); - assertThat(expected).isEqualTo(formData.getFormData()); - } - - @Test - void shouldTransformSimpleDocumentWithoutNamespace() throws ParserConfigurationException, IOException, SAXException { - final Document document = loadDocument("src/test/resources/test3.xml"); - final FormData formData = fimService.transformDocument(document, FormData.builder().build()); - - final Map<String, Object> expected = Map.of( - "fim.S1235", Map.of("label", "Testkey", "value", "Testvalue"), - "fim.S1236", Map.of("label", "fim.S1236", "value", "Testvalue 2")); - assertThat(expected).isEqualTo(formData.getFormData()); - } - - @Test - void shouldTransformDocument() throws ParserConfigurationException, IOException, SAXException { - final Document document = loadDocument("src/test/resources/S17000652V1.4_test01.xml"); - FormData formData = fimService.transformDocument(document, FormData.builder().build()); - - assertThat(formData).isNotNull(); - - final Map<String, Object> expected = Map.of( - "xfd:G17003529", Map.of( - "label", "EfA|SH Standard", - "value", Map.of( - "xfd:G05001479", Map.of( - "label", "nachrichtenkopf", - "value", Map.of( - "xfd:G05001480", Map.of( - "label", "identifikation.nachricht", - "value", Map.of( - "xfd:F05002750", - Map.of("label", "nachrichtenUUID", "value", "d447e43a-5723-4821-a170-cb44d2dbf143"), - "xfd:F05002751", - Map.of("label", "erstellungszeitpunkt", "value", "2022-08-15T09:30:47"), - "xfd:F05002752", - Map.of("label", "nachrichtentyp", "value", "fim.S17000652.17000652001004"), - "xfd:F05002753", - Map.of("label", "dienstname", "value", "urn:fim:Versammlungsanzeige:1.4"))), - "xfd:G05001481", Map.of( - "label", "Leser", - "value", Map.of( - "xfd:F05002754", Map.of("label", "Organisationsname", "value", "Celle"), - "xfd:F05002755", - Map.of("label", "Organisationsschlüssel", "value", "vbe:010550120100"), - "xfd:F05002756", Map.of("label", "Kategorie", "value", "Versammlungsbehörde"))), - "xfd:G05001482", Map.of( - "label", "Autor", - "value", Map.of( - "xfd:F05002754", - Map.of("label", "Organisationsname", "value", - "OSI-Onlinedienst Niedersachsen Versammlungsanzeige"), - "xfd:F05002755", - Map.of("label", "Organisationsschlüssel", "value", "vbe:010550120100"), - "xfd:F05002756", - Map.of("label", "Kategorie", "value", "Engagement- und Hobbyportal"))))), - "xfd:F17005454", Map.of("label", "Datenschutzhinweis DSGVO", "value", "true"), - "xfd:F17005455", Map.of("label", "Zustimmung zu einem digitalen Bescheid", "value", "true"), - "xfd:F17005533", Map.of("label", "UUID", "value", "String"))), - "xfd:F17009191", Map.of("label", "Anzeige durch Person", "value", "true"), - "xfd:F17003371", Map.of("label", "Anzeigenart", "value", "String")); - - assertThat(expected).isEqualTo(formData.getFormData()); - } - - @Test - void shouldFallbackUnknownScheme() { - IncomingFile r1 = IncomingFile.builder().name("src/test/resources/test3/Antrag.xml").file(new File("src/test/resources/test3/Antrag.xml")) - .build(); - IncomingFile r2 = IncomingFile.builder().name("src/test/resources/test3/fim_xtaMetadata.xml").build(); - final FormData initialFormData = FormDataTestFactory.createBuilder().formData(null) - .header(FormHeader.builder().channel("XTA").formEngineName("FIM").build()) - .representations(List.of(r1, r2)).build(); - - FormData formData = fimBasedAdapter.parseFormData(initialFormData); - - assertThat(formData).isNotNull(); - - final Map<String, Object> expected = Map.of( - "xfd:G17003529", Map.of( - "label", "xfd:G17003529", - "value", Map.of( - "xfd:G05001479", Map.of( - "label", "xfd:G05001479", - "value", Map.of( - "xfd:G05001480", Map.of( - "label", "xfd:G05001480", - "value", Map.of( - "xfd:F05002750", - Map.of("label", "xfd:F05002750", "value", "d447e43a-5723-4821-a170-cb44d2dbf143"), - "xfd:F05002751", Map.of("label", "xfd:F05002751", "value", "2022-08-15T09:30:47"), - "xfd:F05002752", - Map.of("label", "xfd:F05002752", "value", "fim.S17000652.17000652001004"), - "xfd:F05002753", - Map.of("label", "xfd:F05002753", "value", "urn:fim:Versammlungsanzeige:1.4"))), - "xfd:G05001481", Map.of( - "label", "xfd:G05001481", - "value", Map.of( - "xfd:F05002754", Map.of("label", "xfd:F05002754", "value", "Celle"), - "xfd:F05002755", Map.of("label", "xfd:F05002755", "value", "vbe:010550120100"), - "xfd:F05002756", Map.of("label", "xfd:F05002756", "value", "Versammlungsbehörde"))), - "xfd:G05001482", Map.of( - "label", "xfd:G05001482", - "value", Map.of( - "xfd:F05002754", - Map.of("label", "xfd:F05002754", "value", - "OSI-Onlinedienst Niedersachsen Versammlungsanzeige"), - "xfd:F05002755", Map.of("label", "xfd:F05002755", "value", "vbe:010550120100"), - "xfd:F05002756", - Map.of("label", "xfd:F05002756", "value", "Engagement- und Hobbyportal"))))), - "xfd:F17005454", Map.of("label", "xfd:F17005454", "value", "true"), - "xfd:F17005455", Map.of("label", "xfd:F17005455", "value", "true"), - "xfd:F17005533", Map.of("label", "xfd:F17005533", "value", "String"))), - "xfd:F17009191", Map.of("label", "xfd:F17009191", "value", "true"), - "xfd:F17003371", Map.of("label", "xfd:F17003371", "value", "String")); - - assertThat(formData.getFormData()).usingRecursiveComparison().isEqualTo(expected); - } - - private Document loadDocument(final String path) throws ParserConfigurationException, IOException, SAXException { - final DocumentBuilder builder = DocumentBuilderFactory.newInstance().newDocumentBuilder(); - return builder.parse(new File(path)); - } -} diff --git a/fim-adapter/src/test/java/de/ozgcloud/eingang/fim/FimServiceTest.java b/fim-adapter/src/test/java/de/ozgcloud/eingang/fim/FimServiceTest.java new file mode 100644 index 0000000000000000000000000000000000000000..4d090842c766264a4886e3251acf72358d0d6152 --- /dev/null +++ b/fim-adapter/src/test/java/de/ozgcloud/eingang/fim/FimServiceTest.java @@ -0,0 +1,226 @@ +package de.ozgcloud.eingang.fim; + +import static org.assertj.core.api.Assertions.*; +import static org.mockito.ArgumentMatchers.*; +import static org.mockito.Mockito.*; + +import java.util.List; +import java.util.Optional; + +import org.apache.commons.lang3.StringUtils; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.Spy; +import org.w3c.dom.Document; + +import com.thedeanda.lorem.LoremIpsum; + +import de.ozgcloud.eingang.common.formdata.FormData; +import de.ozgcloud.eingang.common.formdata.FormData.Representations; +import de.ozgcloud.eingang.common.formdata.FormDataControlTestFactory; +import de.ozgcloud.eingang.common.formdata.FormDataTestFactory; +import de.ozgcloud.eingang.common.formdata.IncomingFile; +import de.ozgcloud.eingang.common.formdata.IncomingFileTestFactory; +import de.ozgcloud.eingang.fim.common.errorhandling.FimException; +import de.ozgcloud.eingang.fim.common.xml.DocumentHelper; + +class FimServiceTest { + + @Spy + @InjectMocks + private FimService service; + @Mock + private FimSchemeHelper schemeHelper; + + @DisplayName("Find primary representation") + @Nested + class TestFindPrimaryRepresentation { + + private final String representationName = LoremIpsum.getInstance().getName(); + private final IncomingFile representationFile = IncomingFileTestFactory.createBuilder() + .name(representationName) + .build(); + private final IncomingFile file = IncomingFileTestFactory.create(); + private final FormData formData = FormDataTestFactory.createBuilder() + .clearRepresentations().representations(List.of(representationFile, file)) + .build(); + + @BeforeEach + void initMocks() { + doReturn(representationName).when(service).getRepresentationName(any()); + } + + @Test + void shouldCallGetRepresentationName() { + service.findPrimaryRepresentation(formData); + + verify(service).getRepresentationName(FormDataTestFactory.FORM_DATA_CONTROL); + } + + @Test + void shouldReturnPrimaryRepresentationIfExists() { + var primaryRepresentation = service.findPrimaryRepresentation(formData); + + assertThat(primaryRepresentation).hasValue(representationFile); + } + + @Test + void shouldReturnEmptyIfMissing() { + var formDataWithoutMatchingRepresentation = FormDataTestFactory.createBuilder().clearRepresentations().representation(file).build(); + + var primaryRepresentation = service.findPrimaryRepresentation(formDataWithoutMatchingRepresentation); + + assertThat(primaryRepresentation).isEmpty(); + } + } + + @DisplayName("Get representation name") + @Nested + class TestGetRepresentationName { + + @Test + void shouldReturnPrimaryRepresentationName() { + var result = service.getRepresentationName(FormDataControlTestFactory.create()); + + assertThat(result).isEqualTo(FormDataControlTestFactory.PRIMARY_FORM_DATA_REPRESENTATION); + } + + @Test + void shouldReturnDefaultNameOnMissingRepresentations() { + var formDataControl = FormDataControlTestFactory.createBuilder().representations(Optional.empty()).build(); + + var result = service.getRepresentationName(formDataControl); + + assertThat(result).isEqualTo(FimService.DEFAULT_FORMDATA_REPRESENTATION_NAME); + } + + @Test + void shouldReturnDefaultOnMissingPrimaryRepresentation() { + var formDataControl = FormDataControlTestFactory.createBuilder() + .representations(Optional.of(Representations.builder().build())) + .build(); + + var result = service.getRepresentationName(formDataControl); + + assertThat(result).isEqualTo(FimService.DEFAULT_FORMDATA_REPRESENTATION_NAME); + } + } + + @DisplayName("Get scheme") + @Nested + class TestGetScheme { + + @Mock + private Document doc; + @Mock + private FimScheme fimScheme; + + private final String schemeName = LoremIpsum.getInstance().getName(); + + @BeforeEach + void initMocks() { + doReturn(schemeName).when(service).getSchemeName(any()); + } + + @Test + void shouldCallGetSchemeName() { + service.getScheme(doc); + + verify(service).getScheme(doc); + } + + @DisplayName("on existing scheme") + @Nested + class TestOnExistingScheme { + + @BeforeEach + void mock() { + when(schemeHelper.getScheme(any())).thenReturn(fimScheme); + } + + @Test + void shouldCallSchemeHelper() { + service.getScheme(doc); + + verify(schemeHelper).getScheme(schemeName); + } + + @Test + void shouldReturnScheme() { + var scheme = service.getScheme(doc); + + assertThat(scheme).isEqualTo(fimScheme); + } + } + + @DisplayName("on missing scheme") + @Nested + class TestOnMissingScheme { + + @BeforeEach + void mock() { + when(schemeHelper.getScheme(any())).thenReturn(null); + when(schemeHelper.getDefaultScheme()).thenReturn(fimScheme); + } + + @Test + void shouldCallSchemeHelperToGetDefaultScheme() { + service.getScheme(doc); + + verify(schemeHelper).getDefaultScheme(); + } + + @Test + void shouldReturnDefaultScheme() { + var scheme = service.getScheme(doc); + + assertThat(scheme).isEqualTo(fimScheme); + } + } + } + + @DisplayName("Get scheme name") + @Nested + class TestGetSchemeName { + + @Mock + private Document doc; + + private final String schemeName = LoremIpsum.getInstance().getName(); + + @Test + void shouldCallExtractSchemeName() { + try (var helper = mockStatic(DocumentHelper.class)) { + helper.when(() -> DocumentHelper.extractSchemeName(doc)).thenReturn(schemeName); + + service.getSchemeName(doc); + + helper.verify(() -> DocumentHelper.extractSchemeName(doc)); + } + } + + @Test + void shouldThrowExceptionOnEmptyName() { + try (var helper = mockStatic(DocumentHelper.class)) { + helper.when(() -> DocumentHelper.extractSchemeName(doc)).thenReturn(StringUtils.EMPTY); + + assertThatThrownBy(() -> service.getSchemeName(doc)).isInstanceOf(FimException.class); + } + } + + @Test + void shouldReturnValue() { + try (var helper = mockStatic(DocumentHelper.class)) { + helper.when(() -> DocumentHelper.extractSchemeName(doc)).thenReturn(schemeName); + + var name = service.getSchemeName(doc); + + assertThat(name).isEqualTo(schemeName); + } + } + } +} \ No newline at end of file diff --git a/fim-adapter/src/test/java/de/ozgcloud/eingang/fim/FimTestConfig.java b/fim-adapter/src/test/java/de/ozgcloud/eingang/fim/FimTestConfig.java index beda270ced46867a3188ec5daa32b21a83dce3a1..c90889e887b1501bac40389fe2aeeff112f73f39 100644 --- a/fim-adapter/src/test/java/de/ozgcloud/eingang/fim/FimTestConfig.java +++ b/fim-adapter/src/test/java/de/ozgcloud/eingang/fim/FimTestConfig.java @@ -30,5 +30,5 @@ import org.springframework.context.annotation.Configuration; @Configuration @EnableAutoConfiguration @ComponentScan("de.ozgcloud.eingang") -public class FimTestConfig { +class FimTestConfig { } diff --git a/fim-adapter/src/test/java/de/ozgcloud/eingang/fim/HeaderMapperTest.java b/fim-adapter/src/test/java/de/ozgcloud/eingang/fim/HeaderMapperTest.java new file mode 100644 index 0000000000000000000000000000000000000000..eef87830a7eaa9b3760d037b07cb9d24dc692315 --- /dev/null +++ b/fim-adapter/src/test/java/de/ozgcloud/eingang/fim/HeaderMapperTest.java @@ -0,0 +1,102 @@ +package de.ozgcloud.eingang.fim; + +import static org.assertj.core.api.Assertions.*; +import static org.mockito.ArgumentMatchers.*; +import static org.mockito.Mockito.*; + +import java.util.List; +import java.util.Optional; + +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.Spy; + +import de.ozgcloud.eingang.common.formdata.FormData; +import de.ozgcloud.eingang.common.formdata.FormDataTestFactory; +import de.ozgcloud.eingang.common.formdata.FormHeader; +import de.ozgcloud.eingang.common.formdata.FormHeaderTestFactory; + +class HeaderMapperTest { + + @Spy + @InjectMocks + private HeaderMapper mapper; + + @DisplayName("Parse formData") + @Nested + class TestParseFormData { + + private final FormData formData = FormDataTestFactory.createBuilder().header(FormHeader.builder().build()).build(); + + @DisplayName("on existing formName") + @Nested + class TestOnExistingFormName { + + @BeforeEach + void initMocks() { + doReturn(Optional.of(FormHeaderTestFactory.FORM_NAME)).when(mapper).getFormName(any()); + } + + @Test + void shouldCallBuildHeader() { + mapper.parseFormData(formData); + + verify(mapper).getFormName(FormDataTestFactory.FORM_DATA); + } + + @Test + void shouldReturnFormDataWithHeader() { + var mappedFormData = mapper.parseFormData(formData); + + assertThat(mappedFormData.getHeader().getFormName()).isEqualTo(FormHeaderTestFactory.FORM_NAME); + } + } + + @DisplayName("on missing formName") + @Nested + class TestOnMissingFormName { + + @BeforeEach + void initMocks() { + doReturn(Optional.empty()).when(mapper).getFormName(any()); + } + + @Test + void shouldReturnOriginFormData() { + var mappedFormData = mapper.parseFormData(formData); + + assertThat(mappedFormData).isEqualTo(formData); + } + } + } + + @DisplayName("Get formName") + @Nested + class TestGetFormName { + + @Test + void shouldCallFimDataUtilToGetValue() { + try (var helper = mockStatic(FimDataUtil.class)) { + mapper.getFormName(FormDataTestFactory.FORM_DATA); + + helper.verify( + () -> FimDataUtil.getValue(FormDataTestFactory.FORM_DATA, List.of("G17003529", "G05001479", "G05001480"), + HeaderMapper.FORM_NAME_KEY)); + } + } + + @Test + void shouldReturnValue() { + try (var helper = mockStatic(FimDataUtil.class)) { + helper.when(() -> FimDataUtil.getValue(any(), any(), any())).thenReturn(Optional.of(FormHeaderTestFactory.FORM_NAME)); + + var formNameOpt = mapper.getFormName(FormDataTestFactory.FORM_DATA); + + assertThat(formNameOpt).hasValue(FormHeaderTestFactory.FORM_NAME); + } + } + } +} \ No newline at end of file diff --git a/fim-adapter/src/test/java/de/ozgcloud/eingang/fim/TestNonStandardAdapter.java b/fim-adapter/src/test/java/de/ozgcloud/eingang/fim/TestNonStandardAdapter.java index 0e4c4730663145c65945af3c44433bf59f793003..944dfd5a961c2f18b3b88a3e82ccd0dd2f1edb48 100644 --- a/fim-adapter/src/test/java/de/ozgcloud/eingang/fim/TestNonStandardAdapter.java +++ b/fim-adapter/src/test/java/de/ozgcloud/eingang/fim/TestNonStandardAdapter.java @@ -23,24 +23,23 @@ */ package de.ozgcloud.eingang.fim; -import org.springframework.stereotype.Service; +import java.util.Optional; + +import org.springframework.stereotype.Component; import org.w3c.dom.Element; -import org.w3c.dom.NodeList; -import java.util.Optional; +import de.ozgcloud.eingang.fim.common.xml.DocumentHelper; -@Service +@Component public class TestNonStandardAdapter extends FimSchemeAdapter { - public FimSchemeIdentifier forIdentifier() { - return FimSchemeIdentifier.fromString("test2"); - } + @Override + public FimSchemeIdentifier getIdentifier() { + return FimSchemeIdentifier.fromString("test2"); + } - public Optional<String> getNameForElement(final Element element) { - final NodeList nameTags = element.getElementsByTagName("non-standard-name"); - if (nameTags.getLength() != 1) { - return Optional.empty(); - } - return Optional.ofNullable(nameTags.item(0).getTextContent()); - } + @Override + public Optional<String> getNameForElement(Element element) { + return DocumentHelper.getChildElement(element, "non-standard-name"); + } } diff --git a/fim-adapter/src/test/java/de/ozgcloud/eingang/fim/ZustaendigeStelleMapperTest.java b/fim-adapter/src/test/java/de/ozgcloud/eingang/fim/ZustaendigeStelleMapperTest.java index 31ddc5d89a23804418867acbe23a3fb58f48ae1d..e287c0b524595da374f45c7df2cc391b095ec3ce 100644 --- a/fim-adapter/src/test/java/de/ozgcloud/eingang/fim/ZustaendigeStelleMapperTest.java +++ b/fim-adapter/src/test/java/de/ozgcloud/eingang/fim/ZustaendigeStelleMapperTest.java @@ -44,7 +44,7 @@ class ZustaendigeStelleMapperTest { assertThat(parsed.getZustaendigeStelles()).hasSize(1).first().extracting(ZustaendigeStelle::getOrganisationseinheitenId) .isEqualTo(FormMetaDataTestFactory.OE_ID); -// assertThat(parsed.getZustaendigeStelle().getOrganisationseinheitenId()).isEqualTo(FormMetaDataTestFactory.OE_ID); + assertThat(parsed.getZustaendigeStelles().get(0).getOrganisationseinheitenId()).isEqualTo(FormMetaDataTestFactory.OE_ID); } @Test @@ -54,12 +54,12 @@ class ZustaendigeStelleMapperTest { assertThat(parsed.getZustaendigeStelles()).hasSize(1).first().extracting(ZustaendigeStelle::getOrganisationseinheitenId) .isNotNull(); -// assertThat(parsed.getZustaendigeStelle()).isNotNull(); + assertThat(parsed.getZustaendigeStelles().get(0)).isNotNull(); } @Test void shouldIgnoreMalformedDestinationId() { - var oeid = mapper.extractOrganisationsEinheitId("quatsch"); + var oeid = mapper.extractOrganisationEinheitId("quatsch"); assertThat(oeid).isEmpty(); } diff --git a/fim-adapter/src/test/resources/antrag.xml b/fim-adapter/src/test/resources/antrag.xml new file mode 100644 index 0000000000000000000000000000000000000000..7b77f0d570d7aa4f484a6a0ec70532f5f627f35b --- /dev/null +++ b/fim-adapter/src/test/resources/antrag.xml @@ -0,0 +1,63 @@ +<fim.S17000652.17000652001004 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xmlns:xsd="http://www.w3.org/2001/XMLSchema" + xmlns="urn:xoev-de:xfall:standard:fim-s17000652_1.4"> + <G17003529> + <G05001479> + <G05001480> + <F05002750>85ad506f-25a2-4a93-a086-b069784c6d60</F05002750> + <F05002751>21.03.2024 08:56:33</F05002751> + <F05002752>fim.S17000652.17000652001004</F05002752> + <F05002753>urn:fim:Versammlungsanzeige:1.4</F05002753> + </G05001480> + <G05001481> + <F05002754>Fachdienst Sicherheit und Ordnung - Kreis Ostholstein</F05002754> + <F05002755>vbe:010550120100</F05002755> + <F05002756>Versammlungsbehörde</F05002756> + </G05001481> + <G05001482> + <F05002754>Dataport</F05002754> + <F05002755>ehp:010100100000</F05002755> + <F05002756>Versammlungsbehörde</F05002756> + </G05001482> + </G05001479> + <F17005454>true</F17005454> + <F17005455>false</F17005455> + <F17005533>85ad506f-25a2-4a93-a086-b069784c6d60</F17005533> + </G17003529> + <F17009191>false</F17009191> + <G17002112> + <F60000228>Jörg</F60000228> + <F60000227>Smith</F60000227> + <G60000086> + <F60000243>Muster</F60000243> + <F60000244>1</F60000244> + <F60000246>12345</F60000246> + <F60000247>Muster</F60000247> + </G60000086> + <F60000242>example@email.de</F60000242> + <F17009011>false</F17009011> + </G17002112> + <F17003371>Anzeigen einer ortsfesten Versammlung (Kundgebung / Demonstration)</F17003371> + <G17005404> + <G17007202> + <F17003373>fsdf</F17003373> + <F17003377>sdf</F17003377> + <G17005406> + <F60000048>2024-03-21</F60000048> + <F17001348>13.5</F17001348> + <F60000049>2024-03-21</F60000049> + <F17001349>15</F17001349> + </G17005406> + </G17007202> + <G17007205> + <F17003379>10</F17003379> + <F17003382>keine</F17003382> + <G17007234> + <F17011826>Nein</F17011826> + </G17007234> + <G17007235> + <F17011827>Nein</F17011827> + </G17007235> + </G17007205> + </G17005404> +</fim.S17000652.17000652001004> \ No newline at end of file diff --git a/fim-adapter/src/test/resources/application-test.yml b/fim-adapter/src/test/resources/application-test.yml index 148c1af75dbdac7d1dff1c5632d01cf06dae9a83..48cef7b0de1443abb0fe6f7b59d660c95704dae8 100644 --- a/fim-adapter/src/test/resources/application-test.yml +++ b/fim-adapter/src/test/resources/application-test.yml @@ -1,4 +1,6 @@ -fim: - schemeLocations: - - fim-s17000652_1.4/S17000652V1.4_xfall.xsd - - test2/test2.xsd \ No newline at end of file +ozgcloud: + eingang: + fim: + schemeLocations: + - fim-s17000652_1.4/S17000652V1.4_xfall.xsd + - test2/test2.xsd \ No newline at end of file diff --git a/pom.xml b/pom.xml index 16a3e1042a919d2fd0c3d4b34734094db45f9e37..a04f8b8d7946bf9e5cd2934586156665d9b37575 100644 --- a/pom.xml +++ b/pom.xml @@ -31,7 +31,7 @@ <parent> <groupId>de.ozgcloud.common</groupId> <artifactId>ozgcloud-common-parent</artifactId> - <version>4.7.0</version> + <version>4.9.0-SNAPSHOT</version> <relativePath/> <!-- lookup parent from repository --> </parent> 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 index dd05b83ee24886341034a8a18ba1e702d5bd5ae1..736dc56bb3c554834dadadb623b38dabadb22847 100644 --- 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 @@ -28,6 +28,7 @@ import java.util.List; import java.util.Map; import java.util.Optional; import java.util.Set; +import java.util.function.Predicate; import java.util.stream.Collector; import java.util.stream.Collectors; import java.util.stream.Stream; @@ -49,6 +50,8 @@ import lombok.extern.log4j.Log4j2; @Log4j2 public class IntelliFormRepresentationAdapter { + private static final Predicate<IncomingFile> HAS_XML_CONTENT_TYPE = file -> file.getContentType().contains("xml"); + static final String INTELLIFORM_TYPENAME = "http://xmlns.cit.de/intelliform/transaction"; static final String FILE = "file"; @@ -64,8 +67,7 @@ public class IntelliFormRepresentationAdapter { "t:customer", "t:customer-id", "t:client", - "t:client-id" - ); + "t:client-id"); public static final List<String> CUSTOM_HEADER_ATTRIBUTE_NAMES = List.of( "u:saml_legacypostkorbhandle", "u:saml_givenname", @@ -77,15 +79,13 @@ public class IntelliFormRepresentationAdapter { "u:saml_postaladdress", "u:saml_postalcode", "u:saml_localityname", - ServiceKontoFactory.KEY_BAYERN_ID_TRUST_LEVEL - ); + ServiceKontoFactory.KEY_BAYERN_ID_TRUST_LEVEL); 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 - ); + LinkedHashMap::new); private final XmlToJavaMapsMapper xmlToJavaMapsMapper; @@ -95,25 +95,23 @@ public class IntelliFormRepresentationAdapter { } 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(); + return streamXMLDocumentsFromRepresentations(formData).filter(this::isIntelliFormDocument).findFirst(); + } + + private boolean isIntelliFormDocument(Document document) { + return document.getDocumentElement().getAttribute("xmlns:t").equals(INTELLIFORM_TYPENAME); } 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(); - } - }); + return formData.getRepresentations().stream().filter(HAS_XML_CONTENT_TYPE).flatMap(this::parseDocument); + } + + private Stream<Document> parseDocument(IncomingFile xmlRepresentation) { + try { + return Stream.of(xmlToJavaMapsMapper.parseAsW3cDocument(xmlRepresentation.getContentStream())); + } catch (TechnicalException exception) { + return Stream.empty(); + } } public FormData adaptByRepresentations(FormData formData) { @@ -125,10 +123,8 @@ public class IntelliFormRepresentationAdapter { .attachments(formData.getAttachments()) .formData(Stream.concat( getFormDataEntriesFromDocument(document, formData.getAttachments()), - Map.of( - HEADER_FIELD, createHeaderMap(document) - ).entrySet().stream() - ).collect(ORDERED_MAP_ENTRY_COLLECTOR)) + Map.of(HEADER_FIELD, createHeaderMap(document)).entrySet().stream()) + .collect(ORDERED_MAP_ENTRY_COLLECTOR)) .build(); } @@ -138,8 +134,7 @@ public class IntelliFormRepresentationAdapter { .map(IncomingFile::getVendorId) .collect(Collectors.toSet()); - return xmlToJavaMapsMapper.mapXmlToJavaMaps(document).entrySet() - .stream() + return xmlToJavaMapsMapper.mapXmlToJavaMaps(document).entrySet().stream() .filter(entry -> !isUploadElementWhichRefersToAttachment(entry.getValue(), attachmentVendorIds)); }