Commit 7e21ebb6 authored by Jonas Waeber's avatar Jonas Waeber
Browse files

Add test and fix some minor issues

parent 41d7f0b2
Pipeline #12337 passed with stages
in 6 minutes
...@@ -104,7 +104,7 @@ class KafkaTopology(private val settings: SettingsLoader) { ...@@ -104,7 +104,7 @@ class KafkaTopology(private val settings: SettingsLoader) {
val report = value.getReport() val report = value.getReport()
if (report.status == ReportStatus.success) { if (report.status == ReportStatus.success) {
ProcessReport( ProcessReport(
report.id, "xml-data-transform",
ReportStatus.success, ReportStatus.success,
1, 1,
1, 1,
...@@ -112,7 +112,7 @@ class KafkaTopology(private val settings: SettingsLoader) { ...@@ -112,7 +112,7 @@ class KafkaTopology(private val settings: SettingsLoader) {
) )
} else { } else {
ProcessReport( ProcessReport(
report.id, "xml-data-transform",
ReportStatus.failure, ReportStatus.failure,
1, 1,
0, 0,
......
...@@ -128,28 +128,32 @@ class SAXContentHandler(key: String, private val identifierFieldName: String, pr ...@@ -128,28 +128,32 @@ class SAXContentHandler(key: String, private val identifierFieldName: String, pr
if (recordTag == localName) if (recordTag == localName)
return return
if (currentElementTag == localName) { when {
if (currentElementTag == identifierFieldName) { currentElementTag == localName -> {
identifier = currentElementContent if (currentElementTag == identifierFieldName) {
identifier = currentElementContent
}
if (innerElements.isEmpty()) {
if (currentElementContent.isNotEmpty()) {
jsonResult[currentElementTag] = currentElementContent
}
} else {
jsonResult[currentElementTag] = innerElements.toMap()
innerElements.clear()
}
currentElementTag = ""
currentElementContent = ""
} }
if (innerElements.isEmpty()) { currentInnerElementTag == localName -> {
if (currentElementContent.isNotEmpty()) { if (currentInnerElementContent.isNotEmpty()) {
jsonResult[currentElementTag] = currentElementContent innerElements.add(Pair(currentInnerElementTag, currentInnerElementContent))
} }
} else { currentInnerElementTag = ""
jsonResult[currentElementTag] = innerElements.toMap() currentInnerElementContent = ""
innerElements.clear()
} }
currentElementTag = "" else -> {
currentElementContent = "" reportText += "Unmatched end element: $localName.\n"
} else if (currentInnerElementTag == localName) {
if (currentInnerElementContent.isNotEmpty()) {
innerElements.add(Pair(currentInnerElementTag, currentInnerElementContent))
} }
currentInnerElementTag = ""
currentInnerElementContent = ""
} else {
reportText += "Unmatched end element: $localName.\n"
} }
} }
......
...@@ -18,11 +18,107 @@ ...@@ -18,11 +18,107 @@
package org.memobase package org.memobase
import com.beust.klaxon.Klaxon
import org.apache.kafka.common.serialization.StringDeserializer
import org.apache.kafka.common.serialization.StringSerializer
import org.apache.kafka.streams.TopologyTestDriver
import org.apache.kafka.streams.test.ConsumerRecordFactory
import org.apache.logging.log4j.LogManager
import org.assertj.core.api.Assertions.assertThat
import org.junit.jupiter.api.TestInstance import org.junit.jupiter.api.TestInstance
import org.junit.jupiter.api.assertAll
import org.junit.jupiter.params.ParameterizedTest
import org.junit.jupiter.params.provider.MethodSource
import org.memobase.testing.EmbeddedSftpServer
import java.io.File
import java.io.FileInputStream
import java.nio.charset.Charset
import java.nio.file.Paths
import java.util.stream.Stream
@TestInstance(TestInstance.Lifecycle.PER_CLASS) @TestInstance(TestInstance.Lifecycle.PER_CLASS)
class TestIntegration { class TestIntegration {
private val log = LogManager.getLogger("TestLogger")
private val resourcePath = "src/test/resources/data"
private fun readFile(fileName: String): String {
return File("$resourcePath/$fileName").readText(Charset.defaultCharset())
}
private val sftpServer = EmbeddedSftpServer(22000, "user", "password")
@ParameterizedTest
@MethodSource("integrationTestParams")
fun `test kafka integration single record`(params: TestParams) {
sftpServer.putFile(
"/memobase/test${params.count}/data.xml",
FileInputStream("$resourcePath/${params.count}/data.xml")
)
val service = Service("test${params.count}.yml")
val testDriver = TopologyTestDriver(service.topology, service.settings.kafkaStreamsSettings)
val factory = ConsumerRecordFactory(
StringSerializer(), StringSerializer()
)
testDriver.pipeInput(
factory.create(
service.settings.inputTopic, params.inputKey, readFile("${params.count}/input.json")
)
)
val record = testDriver.readOutput(
service.settings.outputTopic,
StringDeserializer(),
StringDeserializer()
)
val reportedRecord = testDriver.readOutput(
"${service.settings.outputTopic}-reporting",
StringDeserializer(),
StringDeserializer()
)
val data = reportedRecord.value()
val report = Klaxon().parse<Report>(data)
val processReportRecord = testDriver.readOutput(
service.settings.processReportTopic,
StringDeserializer(),
StringDeserializer()
)
val processReport = Klaxon().parse<ProcessReport>(processReportRecord.value())
assertAll("check single record transform",
{
assertThat(record)
.isNotNull
.hasFieldOrPropertyWithValue("key", params.outputKey)
.hasFieldOrPropertyWithValue("value", readFile("${params.count}/output.json"))
},
{
assertThat(report)
.isNotNull
.isEqualTo(params.expectedOutputReport)
},
{
assertThat(processReport)
.isNotNull
.isEqualTo(params.expectedOutputProcessReport)
}
)
}
fun integrationTestParams() = Stream.of(
TestParams(
1,
"simple test",
"data.xml",
"ADG-102683",
Report("ADG-102683", ReportStatus.success, "Successfully transformed xml to json!"),
ProcessReport("xml-data-transform", ReportStatus.success, 1, 1, 0)
)
)
} }
\ No newline at end of file
...@@ -42,7 +42,7 @@ ...@@ -42,7 +42,7 @@
</xsl:template> </xsl:template>
<!-- content of typeLabel is transformed to an element name and content of child node is copied to it--> <!-- content of typeLabel is transformed to an element name and content of child node is copied to it-->
<xsl:template match="description[@typeLabel] | alternativeTitle[@typeLabel] | subject[@typeLabel] | relation[@typeLabel]"> <xsl:template match="description[@typeLabel] | alternativeTitle[@typeLabel] | subject[@typeLabel]">
<xsl:variable name="typeLabel" select="@typeLabel"/> <xsl:variable name="typeLabel" select="@typeLabel"/>
<xsl:element name="{$typeLabel}"> <xsl:element name="{$typeLabel}">
<xsl:value-of select="child::*"/> <xsl:value-of select="child::*"/>
...@@ -50,37 +50,12 @@ ...@@ -50,37 +50,12 @@
</xsl:template> </xsl:template>
<!-- content of typeLabel is copied as content of the node --> <!-- content of typeLabel is copied as content of the node -->
<xsl:template match="format/medium | format/dataFormat/captioningFormat | type/genre"> <xsl:template match="format/medium | format/dataFormat/captioningFormat | type/*">
<xsl:element name="{local-name()}"> <xsl:element name="{local-name()}">
<xsl:value-of select="@typeLabel | @language"/> <xsl:value-of select="@typeLabel | @language"/>
</xsl:element> </xsl:element>
</xsl:template> </xsl:template>
<xsl:template match="type/objectType">
<xsl:element name="objectType">
<xsl:choose>
<xsl:when test="matches(@typeLabel,'film','i')">
<xsl:text>Film</xsl:text>
</xsl:when>
<xsl:when test="matches(@typeLabel,'photograph|foto','i')">
<xsl:text>Foto</xsl:text>
</xsl:when>
<xsl:when test="matches(@typeLabel,'radio','i')">
<xsl:text>Radio</xsl:text>
</xsl:when>
<xsl:when test="matches(@typeLabel,'television|tv','i')">
<xsl:text>TV</xsl:text>
</xsl:when>
<xsl:when test="matches(@typeLabel,'ton|sound','i')">
<xsl:text>Ton</xsl:text>
</xsl:when>
<xsl:when test="matches(@typeLabel,'video','i')">
<xsl:text>Video</xsl:text>
</xsl:when>
</xsl:choose>
</xsl:element>
</xsl:template>
<xsl:template match="identifier"> <xsl:template match="identifier">
<xsl:variable name="typeLabel" select="@typeLabel"/> <xsl:variable name="typeLabel" select="@typeLabel"/>
<xsl:element name="identifier{$typeLabel}"> <xsl:element name="identifier{$typeLabel}">
...@@ -96,48 +71,21 @@ ...@@ -96,48 +71,21 @@
<xsl:value-of select="."/> <xsl:value-of select="."/>
</xsl:element> </xsl:element>
</xsl:for-each> </xsl:for-each>
<xsl:for-each select="width | height">
<xsl:variable name="local" select="local-name()"/>
<xsl:variable name="unit" select="@unit"/>
<xsl:element name="{$local}">
<xsl:value-of select="concat(., ' ', $unit)"/>
</xsl:element>
</xsl:for-each>
<xsl:for-each select="audioTrackConfiguration">
<xsl:element name="audioTrackConfiguration">
<xsl:value-of select="@typeLabel"/>
</xsl:element>
</xsl:for-each>
</xsl:template> </xsl:template>
<!-- ToDo: role auslesen und dabei besitzende Insitution ausschliessen, producer auf Grund Rolle in eigenes Feld -->
<xsl:template match="contributor | creator | publisher"> <xsl:template match="contributor | creator | publisher">
<xsl:variable name="type" select="local-name()"/> <xsl:variable name="type" select="local-name()"/>
<xsl:for-each select="."> <xsl:for-each select=".">
<xsl:variable name="role" select="child::role/@typeLabel[. != '']"/>
<xsl:choose> <xsl:choose>
<xsl:when test="$role = 'ResponsibleInstitution'"/>
<xsl:when test="$role = 'Producer'">
<xsl:choose>
<xsl:when test="child::organisationDetails">
<xsl:element name="producerCorporateBodyName">
<xsl:value-of select="descendant::organisationName"/>
</xsl:element>
</xsl:when>
<xsl:when test="child::contactDetails">
<xsl:element name="producerPersonName">
<xsl:value-of select="descendant::name"/>
</xsl:element>
</xsl:when>
</xsl:choose>
</xsl:when>
<xsl:when test="child::organisationDetails"> <xsl:when test="child::organisationDetails">
<xsl:element name="{$type}CorporateBody"> <xsl:element name="{$type}CorporateBody">
<xsl:element name="name"> <xsl:element name="name">
<xsl:value-of select="descendant::organisationName"/> <xsl:value-of select="descendant::organisationName"/>
</xsl:element> </xsl:element>
<xsl:if test="$role"> <xsl:if test="child::role">
<xsl:element name="role"> <xsl:element name="role">
<xsl:value-of select="$role"/> <xsl:value-of select="child::role[@typeLabel]"/> <!-- funktioniert noch nicht -->
</xsl:element> </xsl:element>
</xsl:if> </xsl:if>
</xsl:element> </xsl:element>
...@@ -147,9 +95,9 @@ ...@@ -147,9 +95,9 @@
<xsl:element name="name"> <xsl:element name="name">
<xsl:value-of select="descendant::name"/> <xsl:value-of select="descendant::name"/>
</xsl:element> </xsl:element>
<xsl:if test="$role"> <xsl:if test="child::role">
<xsl:element name="role"> <xsl:element name="role">
<xsl:value-of select="$role"/> <xsl:value-of select="child::role[@typeLabel]"/> <!-- funktioniert noch nicht -->
</xsl:element> </xsl:element>
</xsl:if> </xsl:if>
</xsl:element> </xsl:element>
...@@ -160,12 +108,12 @@ ...@@ -160,12 +108,12 @@
<xsl:template match="rights[@typeLabel='Access']/ns2:rights"> <xsl:template match="rights[@typeLabel='Access']/ns2:rights">
<xsl:if test="matches(.,'onsite')"> <xsl:if test="matches(.,'onsite')">
<xsl:element name="accessPhysical"> <xsl:element name="accessPhsyical">
<xsl:text>onsite</xsl:text> <xsl:text>onsite</xsl:text>
</xsl:element> </xsl:element>
</xsl:if> </xsl:if>
<xsl:if test="matches(.,'noonsite')"> <xsl:if test="matches(.,'noonsite')">
<xsl:element name="accessPhysical"> <xsl:element name="accessDigital">
<xsl:text>noonsite</xsl:text> <xsl:text>noonsite</xsl:text>
</xsl:element> </xsl:element>
</xsl:if> </xsl:if>
...@@ -192,13 +140,7 @@ ...@@ -192,13 +140,7 @@
</xsl:element> </xsl:element>
</xsl:template> </xsl:template>
<xsl:template match="ns2:source"> <xsl:template match="date">
<xsl:element name="source">
<xsl:value-of select="."/>
</xsl:element>
</xsl:template>
<xsl:template match="date | temporal">
<xsl:for-each select="."> <xsl:for-each select=".">
<xsl:choose> <xsl:choose>
<xsl:when test="child::created"> <xsl:when test="child::created">
...@@ -211,87 +153,14 @@ ...@@ -211,87 +153,14 @@
<xsl:call-template name="dates"/> <xsl:call-template name="dates"/>
</xsl:element> </xsl:element>
</xsl:when> </xsl:when>
<xsl:when test="child::PeriodOfTime">
<xsl:element name="temporal">
<xsl:choose>
<xsl:when test="descendant::periodName">
<xsl:value-of select="descendant::periodName"/>
</xsl:when>
<xsl:otherwise>
<xsl:call-template name="dates"/>
</xsl:otherwise>
</xsl:choose>
</xsl:element>
</xsl:when>
</xsl:choose> </xsl:choose>
</xsl:for-each> </xsl:for-each>
</xsl:template> </xsl:template>
<!-- ToDo: ausbauen für alle attributes von date -->
<xsl:template name="dates"> <xsl:template name="dates">
<xsl:for-each select="child::*"> <xsl:for-each select="child::*">
<xsl:variable name="startDate" select="@startDate[. != '']"/> <xsl:value-of select="@startDate"/>
<xsl:variable name="startYear" select="@startYear[. != '']"/>
<xsl:variable name="startTime" select="@startTime[. != '']"/>
<xsl:variable name="endDate" select="@endDate[. != '']"/>
<xsl:variable name="endYear" select="@endYear[. != '']"/>
<xsl:variable name="period" select="@period[. != '']"/>
<xsl:choose>
<!-- Combinations which are not present in created/issued/temporal and are not processed:
* endYear and startDate
* period and endDate and startYear
* period and endYear and startDate
* startTime in another combination but with startDate
* period and endDate only
-->
<xsl:when test="$startDate and not($endDate | $endYear | $period | $startTime)">
<xsl:value-of select="$startDate"/>
</xsl:when>
<xsl:when test="$startYear and not($endDate | $endYear | $period | $startTime)">
<xsl:value-of select="$startYear"/>
</xsl:when>
<xsl:when test="$startDate and $endDate and not($period | $startTime)">
<xsl:value-of select="concat($startDate, '/', $endDate)"/>
</xsl:when>
<xsl:when test="$startYear and $endDate and not($period | $startTime)">
<xsl:value-of select="concat($startYear, '/', $endDate)"/>
</xsl:when>
<xsl:when test="$startYear and $endYear and not($period | $startTime)">
<xsl:value-of select="concat($startYear, '/', $endYear)"/>
</xsl:when>
<xsl:when test="$startTime">
<xsl:value-of select="concat($startDate, 'T', $startTime)"/>
</xsl:when>
<xsl:when test="$endDate and not ($startDate | $startYear | $period)">
<xsl:value-of select="concat('?/', $endDate)"/>
</xsl:when>
<xsl:when test="$endYear and not ($startDate | $startYear | $period)">
<xsl:value-of select="concat('?/', $endYear)"/>
</xsl:when>
<xsl:when test="$period and not($endDate | $endYear | $startDate | $startYear)">
<xsl:value-of select="$period"/>
</xsl:when>
<xsl:when test="$period and $startDate and not ($endDate | $endYear)">
<xsl:value-of select="concat($period, ' ', $startDate)"/>
</xsl:when>
<xsl:when test="$period and $startYear and not ($endDate | $endYear)">
<xsl:value-of select="concat($period, ' ', $startYear)"/>
</xsl:when>
<xsl:when test="$period and $startDate and $endDate">
<xsl:value-of select="concat($period, ' ', $startDate, '/', $endDate)"/>
</xsl:when>
<xsl:when test="$period and $startYear and $endYear">
<xsl:choose>
<xsl:when test="matches(@period,concat(@startYear, '-', @endYear))">
<xsl:value-of select="concat($startYear, '/', $endYear)"/>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="concat($period, ' ', $startYear, '/', $endYear)"/>
</xsl:otherwise>
</xsl:choose>
</xsl:when>
</xsl:choose>
</xsl:for-each> </xsl:for-each>
</xsl:template> </xsl:template>
......
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<!-- <foxml:digitalObject VERSION="1.1" PID="memobase:ADG-102683"
~ xml-data-transform xmlns:foxml="info:fedora/fedora-system:def/foxml#"
~ Copyright (C) 2020 Memoriav xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
~ xsi:schemaLocation="info:fedora/fedora-system:def/foxml# http://www.fedora.info/definitions/1/0/foxml1-1.xsd">
~ This program is free software: you can redistribute it and/or modify <foxml:objectProperties>
~ it under the terms of the GNU Affero General Public License as published by <foxml:property NAME="info:fedora/fedora-system:def/model#state" VALUE="Active"/>
~ the Free Software Foundation, either version 3 of the License, or <foxml:property NAME="info:fedora/fedora-system:def/model#label" VALUE="Ausgrabung_Crestaulta"/>
~ (at your option) any later version. <foxml:property NAME="info:fedora/fedora-system:def/model#ownerId" VALUE="ADG"/>
~ <foxml:property NAME="info:fedora/fedora-system:def/model#createdDate" VALUE="2019-11-08T13:11:41.422Z"/>
~ This program is distributed in the hope that it will be useful, <foxml:property NAME="info:fedora/fedora-system:def/view#lastModifiedDate" VALUE="2019-11-08T13:11:49.329Z"/>
~ but WITHOUT ANY WARRANTY; without even the implied warranty of </foxml:objectProperties>
~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the <foxml:datastream ID="AUDIT" STATE="A" CONTROL_GROUP="X" VERSIONABLE="false">
~ GNU Affero General Public License for more details. <foxml:datastreamVersion ID="AUDIT.0" LABEL="Audit Trail for this object" CREATED="2019-11-08T13:11:41.422Z" MIMETYPE="text/xml" FORMAT_URI="info:fedora/fedora-system:format/xml.fedora.audit">
~ <foxml:xmlContent>
~ You should have received a copy of the GNU Affero General Public License <audit:auditTrail xmlns:audit="info:fedora/fedora-system:def/audit#">
~ along with this program. If not, see <https://www.gnu.org/licenses/>. <audit:record ID="AUDREC1">
--> <audit:process type="Fedora API-M"/>
<root> <audit:action>addDatastream</audit:action>
<creator> <audit:componentID>TRANSFORMED_METADATA_0</audit:componentID>
<name>Sebastian</name> <audit:responsibility>fedoraAdmin</audit:responsibility>
<role>Autor</role> <audit:date>2019-11-08T13:11:42.157Z</audit:date>
</creator> <audit:justification></audit:justification>
<date>1928</date> </audit:record>
</root> <audit:record ID="AUDREC2">
<audit:process type="Fedora API-M"/>
<audit:action>addDatastream</audit:action>
<audit:componentID>THUMBNAIL_0</audit:componentID>
<audit:responsibility>fedoraAdmin</audit:responsibility>
<audit:date>2019-11-08T13:11:49.204Z</audit:date>
<audit:justification></audit:justification>
</audit:record>
<audit:record ID="AUDREC3">
<audit:process type="Fedora API-M"/>
<audit:action>modifyDatastreamByValue</audit:action>
<audit:componentID>DC</audit:componentID>
<audit:responsibility>fedoraAdmin</audit:responsibility>
<audit:date>2019-11-08T13:11:49.251Z</audit:date>
<audit:justification></audit:justification>
</audit:record>
<audit:record ID="AUDREC4">
<audit:process type="Fedora API-M"/>
<audit:action>addDatastream</audit:action>
<audit:componentID>ACCESSCOPY_0</audit:componentID>
<audit:responsibility>fedoraAdmin</audit:responsibility>
<audit:date>2019-11-08T13:11:49.329Z</audit:date>
<audit:justification></audit:justification>
</audit:record>
</audit:auditTrail>
</foxml:xmlContent>
</foxml:datastreamVersion>
</foxml:datastream>
<foxml:datastream ID="DC" STATE="A" CONTROL_GROUP="X" VERSIONABLE="true">
<foxml:datastreamVersion ID="DC1.0" LABEL="Dublin Core Record for this object" CREATED="2019-11-08T13:11:41.422Z" MIMETYPE="text/xml" FORMAT_URI="http://www.openarchives.org/OAI/2.0/oai_dc/" SIZE="393">
<foxml:xmlContent>
<oai_dc:dc xmlns:oai_dc="http://www.openarchives.org/OAI/2.0/oai_dc/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.openarchives.org/OAI/2.0/oai_dc/ http://www.openarchives.org/OAI/2.0/oai_dc.xsd">
<dc:title>Ausgrabung_Crestaulta</dc:title>
<dc:identifier>memobase:ADG-102683</dc:identifier>
</oai_dc:dc>
</foxml:xmlContent>
</foxml:datastreamVersion>
<foxml:datastreamVersion ID="DC.1" LABEL="Dublin Core Record for this object" CREATED="2019-11-08T13:11:49.251Z" MIMETYPE="text/xml" FORMAT_URI="http://www.openarchives.org/OAI/2.0/oai_dc/" SIZE="600">
<foxml:xmlContent>
<oai_dc:dc xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:oai_dc="http://www.openarchives.org/OAI/2.0/oai_dc/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.openarchives.org/OAI/2.0/oai_dc/ http://www.openarchives.org/OAI/2.0/oai_dc.xsd">
<dc:title>Ausgrabung Crestaulta</dc:title>
<dc:type>memobase:MemobaseDocumentModel-1.0</dc:type>
<dc:identifier>memobase:ADG-102683</dc:identifier>
<dc:source>102683</dc:source>
<dc:language>en</dc:language>
<dc:relation>memobase:ADG-68432</dc:relation>
<dc:rights>onsite,public</dc:rights>
</oai_dc:dc>
</foxml:xmlContent>
</foxml:datastreamVersion>
</foxml:datastream>
<foxml:datastream ID="TRANSFORMED_METADATA_0" STATE="A" CONTROL_GROUP="X" VERSIONABLE="true">
<foxml:datastreamVersion ID="TRANSFORMED_METADATA_0.0" LABEL="Internal Memobase Metadata" CREATED="2019-11-08T13:11:42.157Z" MIMETYPE="text/xml" FORMAT_URI="urn:ebu:metadata-schema:ebuCore_2012" SIZE="3183">
<foxml:xmlContent>
<ebuCoreMain xmlns="urn:ebu:metadata-schema:ebuCore_2012" xmlns:ns2="http://purl.org/dc/elements/1.1/" xml:lang="de">
<coreMetadata>
<title>
<ns2:title>Ausgrabung Crestaulta</ns2:title>
</title>
<alternativeTitle typeLabel="SerieTitle">
<ns2:title>Grabung Walo Burkart und Karl Keller-Tarnuzzer, Lumbrein-Surin (Crestaulta)</ns2:title>
</alternativeTitle>
<creator>
<contactDetails>
<name>Karl Keller-Tarnuzzer</name>
</contactDetails>
<role typeLabel="Author"></role>
</creator>
<subject typeLabel="Keywords">
<ns2:subject>Ausgrabung, Archäologie</ns2:subject>
</subject>
<description typeLabel="Abstract">
<ns2:description>Herdstelle in Fläche D, 2. Situation (mittlere Schicht)