Hintergrund
Zur Marktkommunikation im regulierten Energiemarkt sind (durch die Spezifikationen des BDEW/DVGW) EDIFACT Nachrichten vorgegeben. Da das EDIFACT Datenformat zur technischen Verarbeitung wenig geeignet ist, definiert üblicherweise ein Backend-System zur Verarbeitung der fachlichen Prozesse (wie z.B. ISU, SXP, MBS) ein anderes Datenformat. Eine Hauptaufgabe der technischen Marktkommunikation (wie der B2B) ist es somit das Mapping der Nachrichten (in beiden Richtungen) zwischen EDIFACT und dem Datenformat des zugehörigen Backends (je nach fachlichem Prozess) herzustellen. Im Zuge dessen wurde das “edi-json” entwickelt, eine JSON Repräsentation/Library der EDIFACT, welches als Datenformat von (künftigen) Backend-Systemen von Arvato verwendet wird, z.B. SXP, AEP Mako Cloud, PKS.
Technisch wird die Konvertierung durch eine eigenständige Applikation realisiert, die das Nachrichten-Mapping per REST durch einen (Micro-)Service anbietet, der von allen Systemen verwendet werden kann.
Aufbau
Der Microservice ist eine eigenständige SpringBoot Applikation, die einen Post Endpunkt pro Konvertierungrichtung anbietet. Streng genommen wäre hier die GET Methode angebrachter, diese übermittelt ihre Daten aber nicht im Request Body, der bei einer Größe von potentiell mehreren Megabytes die bessere Option darstellt. Alternativ wäre eine Datenübermittlung im Rahmen eines File Uploads. Dieser Weg wurde aber hier nicht gewählt.
Unterstützte Formate und Sprache
Ab der Formatumstellung im Oktober 2022 wird das edi-json Mapping von allen EDIFACT Formatversionen des deutschen Strommarktes (definiert durch den BDEW) unterstützt. Die edi-json Datenstruktur liegt dabei ab den Formatversionen zur Umstellung Oktober 2022 in deutscher Sprache vor. Die Benennungen der Felder erfolgen dabei direkt anhand der Spezifikationen des BDEWs aus dem MIG Dokumenten, sodass die edi-json hiermit fachlich leicht lesbar werden.
Für EDIFACT Formatversionen vor der Formatumstellung im Oktober 2022 wird nur das Mapping ausgewählter wichtiger Formate unterstützt, nämlich: UTILMD, MSCONS, ORDERS, ORDRSP, IFTSTA, APERAK. Zudem liegt hier das edi-json in der Regel nur in englischer Sprache vor.
Sollte das edi-json Mapping auch von Gas oder anderen EDIFACT Formaten benötigt werden, so kann dies beauftragt werden.
Datenverarbeitung
Die übermittelten Daten werden synchron konvertiert und die Resultate im Responsebody übertragen.
Konfiguration des Microservice
Der Microservice wird über die Datei application.yml
konfiguriert. Relevante Settings dabei
- server.port - Der Port unter den der Service erreichbar sein soll
- andere aus SpringBoot bekannte parameter wie logging etc.
Versionsinfo
Die aktuelle Version des Microservice kann mit Hilfe des Endpunkts /actuator/info abgerufen werden.
Release Download
Der edi-json.converter
kann als Docker Image docker-nob-erp.next-level-apps.com/edi-json.converter:${EDIC_VER} bezogen werden oder über das PrivateDL (mit berechtigtem Zugang) als Artefakt heruntergeladen werden.
Release Prozess
Mindestens zu jeder neuen Formatumstellung oder bei korrigierten Lesefassungen (mit für das Mapping relevanten Änderungen auf unterstützten Formatversionen) wird ein neues Release von uns bereit gestellt (analog zum Validation Content (VC)). Ansonsten gibt es keinen regulären Release Prozess.
Ein edi-json.converter Release ist i.A. unabhängig von anderen Releases (z.B. B2B oder VC).
Die Release Notes zum edi-json.converter finden sich im hier.
Deployment
Docker Container
Beispiel Eintrag in docker-compose.yml zum Start einer edi-json.converter Instanz.
services:
edic01:
image: docker-nob-erp.next-level-apps.com/edi-json.converter:${EDIC_VER}
hostname: edic01
container_name: edic01
restart: always
command: "-Xmx4g"
ports:
- "8090:8080"
# management server port
- "9001:9001"
# debug
# - "5005:5005"
environment:
- TZ=Europe/Berlin
- JAVA_OPTS= -XX:+ExitOnOutOfMemoryError
# debug
# - JAVA_TOOL_OPTIONS=-agentlib:jdwp=transport=dt_socket,address=5005,server=y,suspend=n
volumes:
- ./logs_container:/logs
- /etc/localtime:/etc/localtime:ro
Start ohne Docker
Das Artefakt des edi-json.converters kann einfach mit dem Befehl
java --add-opens java.base/java.lang=ALL-UNNAMED --add-opens java.base/java.util=ALL-UNNAMED -jar edi-json.converter.jar
im Verzeichnis des Artefakts ausgeführt werden.
Hinweis: Der edi-json.converter läuft mit Java 17, welches hierbei verwendet werden muss.
Der ausgeführte Service (zum Beispiel sein Port via server.port) kann dabei durch ein application.yml File, welches neben der jar gelegt wird, konfiguriert werden. Die Default Einstellungen aus dem Artefakt sehen wie folgt aus:
server:
port: 8080
logging:
level:
root: INFO
com.nextlevel.edi.json.converter: INFO
spring:
main:
allow-bean-definition-overriding: true
management:
server:
port: 9001
endpoint:
info:
enabled: true
health:
show-details: always
Verwendung zusammen mit der B2B
Schnell-Customizing
Es folgt ein minimales Customizing. Dieses stellt die Edi-Json Grundfunktionalitäten zur Verfügung, die in den folgenden Abschnitten genauer erläutert werden.
globalProperties:
EDIJSON_CONVERTER_URL: "http://edi-json-converter:8080"
services:
"ProcessTrigger":
name: EdiJsonMeta an ProcessTrigger
class: com.nextlevel.services.outbound.http.ProcessTriggerService
type: REST
direction: OUT
properties:
URL: "http://sxp-processtrigger-sim:8080"
MONITOR_OUTPUT: true
"EdiJsonInbound":
name: EdiJson Receiver
type: REST
channel: OUT_SEP
direction: IN
actions:
"SXP-ProcessTrigger #730":
id: 730
class: org.b2bbp.runtime.actions.internal.SetPropertyAction
description: 'Ruft den Service auf, der das EdiJson-Meta an den SXP-ProcessTrigger übergibt.'
properties:
B3P_USED_SERVICE_ID:
value: "ProcessTrigger"
techMon: true
"EdiJson-2-Edifact #731":
id: 731
class: com.nextlevel.edifactjson.mapping.EdiJson2EdifactMappingAction
description: 'Action, die das EdiJson in eine Edifact konvertiert.'
properties:
URL:
value: "http://edi-json-converter:8080"
techMon: true
channels:
-
id: IN_SXP
direction: IN
actions:
"ValidatorAction": true
"Contrl erzeugen": true
"Aperak erzeugen": true
"Übergabe an SXP-ProcessTrigger #730": true
"ErrorMailHandler": false
-
id: OUT_SXP
direction: OUT
actions:
"EdiJson-2-Edifact #731": true
"IndexingService Volltext": true
"Msg versenden (Mail/AS2)": true
"ErrorMailHandler": false
Einleitung
Die folgenden zwei Schaubilder zeigen schematisch wie der edi-json.converter Microservice zusammen mit der B2B und einem angeschlossenen Backend (z.B. der SXP Process Engine) konfiguriert werden kann, welches über edi-json (mit der B2B) kommuniziert. Dabei sind die folgenden zwei Kommunikationsrichtungen zu beachten:
Markt -> Backend (Edifact -> JSON)
Innerhalb der B2B findet zunächst eine normale Nachrichtenverarbeitung statt. Hier findet keine Push-Kommunikation statt. Es wird nur ein GET Endpoint angeboten, der es erlaubt über die MessageId einer verabeiteten Nachricht diese im JSON-Format abzurufen.
Eine Push-Kommunikation kann jedoch separat über den ProcessTrigger realisiert werden: Am Ende der Verarbeitung wird der ProcessTriggerService im Channel aufgerufen, welches ein MetaDaten-JSON ans Backend-System sendet. Dieses enthält u.a. die MessageId.
Nach Abschluss der Verarbeitung kann die JSON-Representation der verarbeiteten Edifact über den folgenden B2B REST Endpoint (tatsächliche Adresse über Swagger einsehbar) erhalten werden.
GET [b2b]/api/edifactjson/v1/edifact/{messageid}
Dabei wird zunächst die Ursprungsnachricht anhand der messageId aus der Datenbank geladen. Wurden einige Vorgänge der Nachricht per APERAK abgelehnt, so wird nur die “gekürzte” EDIFACT der APERAK-validen Vorgänge geladen. Ist die verarbeitete Ursprungsnachricht keine Edifact, sondern ein edi-json, so wird dieses direkt zurückgegeben. Im Fall einer Edifact spricht die B2B mit dieser dann den edi-json.converter Microservice an, um diese in ein edi-json zu mappen.
Für die v2 des edi-json Konvertierungsservices wurde die Schnittstelle edifactjson um den Parameter “ignoreSegmentIdentifyErrors” erweitert. Wird hierfür “true” angegeben, werden evtl. auftretende Probleme mit der EDIFACT-Struktur ignoriert. Dies ist der Standardfall. Wird “false” angegeben, werden diese Probleme als Fehler behandelt und die Konvertierung wird abgebrochen. Im Fehler fall wird ein HTTP-500 Fehler mit der entsprechenden Fehlermeldung zurückgegeben.
Dieser REST Endpunkt unterscheidet dabei die folgenden Fehlerklassen für den Fall, dass bei der Anfrage kein edi-json erfolgreich zurückgegeben werden kann:
Fehlerfall | HTTP Status | Fehlerklasse (Response-Body -> details) |
---|---|---|
Autorisierung an B2B fehlgeschlagen | 403 | ACCESS_DENIED - Access is denied |
MessageId aus Abfrage ist in B2B DB nicht vorhanden oder vorhandener aber hat keine Ursprungsnachricht (BASE_MESSAGE) z.B. Job-Eintrag | 404 | MESSAGE_ID_NOT_FOUND - MessageId not found |
Ursprungsnachricht (BASE_MESSAGE) zu MessageId ist weder eine Edifact oder ein edi-json | 404 | WRONG_MESSAGE_FORMAT - The message is neither an edifact nor an edi-json |
Edifact zur der Nachricht konnte nicht erfolgreich vom edi-json.converter gemappt werden | 500 | EDIFACT_CONVERSION_FAILURE - Edifact to edi-json conversion failed |
edi-json.converter ist (vom B2B) nicht erreichbar | 500 | CONVERTER_EXCEPTION - Edi-json converter is unavailable or could not handle the requested message |
edi-json.converter ist in B2B nicht konfiguriert | 500 | CONVERTER_NOT_CUSTOMIZED - This service is inoperational because the global property EDIJSON_CONVERTER_URL could not be read |
B2B nicht erreichbar | 500 | kein B2B Fehlercode Body |
B2B DB Fehler/nicht erreichbar | 503 | B2B_DATABASE_UNAVAILABLE - B2B database is not available |
Seine Base URL muss dazu in der folgenden GlobalProperty hinterlegt sein.
EDIJSON_CONVERTER_URL = http://<converter_server>:<converter_port>
Der HATEOAS-Wrapper der B2B bei der JSON Convertierung hat die folgende Struktur:
{
"data": "edi-json",
"links": []
}
Es können nur nicht archivierte Nachrichten, bei denen das Attribut B3P_BASE_MESSAGE
eine Edifact Nachricht enthält abgerufen werden.
Backend -> Markt (JSON -> Edifact)
Die Edifacts werden im definierten JSON Format (gemäß edi-json-model, inklusive Hateoas-Wrapper) mit UTF-8 Encoding per POST an den Endpunkt (tatsächliche Adresse über Swagger einsehbar) gesendet.
POST [b2b]/api/edifactjson/v1/queue/{priority}
Wird keine Priorität angegeben nimmt die B2B als default-Wert LOW an. Dies entspricht dem üblichen Default-Wert. In der B2B muss dazu ein passiver Pseudo-Inbound-Service angelegt werden, der die Nachrichtenverabeitung mit einem bestimmten Channel in Queue leitet.
Die ID des Services kann abweichend vom Defaultwert in der folgenden GlobalProperty definiert werden, welche nach Neustart aktiv wird:
INBOUND_EDIJSON_SERVICE = My_Json_Inbound_Service (Default: EdiJsonInbound)
Noch vor der Queue durchläuft das JSON die Formaterkennung, welche aus den unterstützten JSON Formate in der HATEOAS-Wrapper Struktur die entsprechenden Daten auslesen kann. (Im Formatobjekt ist das Attribut UtilRef
nicht befüllt.)
Nachdem die Nachricht in der Queue abgelegt wurde wird der Request beendet und die Id der neuen Nachricht im ResponseBody zurück geschickt.
Die Verarbeitung der Nachricht hat zu diesem Zeitpunkt noch nicht begonnen.
Die zurückgegebene ID hat die folgende Form:
<B2BMessageId>_<B2BQueueId>
Die Konvertierung findet hier innerhalb eines Outbound-Channels statt, in welchem die Action EdiJson2EdifactMappingAction konfiguriert werden muss.
Debuggen
- in der docker-compose.yml die Zeilen unter # debug aktivieren
- bei
ports
- bei
environment
- bei
- Debugger konfigurieren
- Datei liegt unter: .runConfigurations/localhost_5005.run.xml
- diese als Debug-Konfiguration verwenden
- (IntelliJ Ultimate: Datei im Viewer anschauen, oberhalb des Codes Hinweis “Open Run/Debug Configurations” anklicken
- Breakpoints setzen
- Container starten
- Debugger in IDE starten
- Rest-Calls durchführen (z. B. mit rest-api.http in IntelliJ)
- Programmlauf stoppt an Breakpoints