Zum Hauptinhalt springen

Java-SDK

Verwaltungssystem implementieren

Empfangende Systeme (in der Regel: Verwaltungssysteme) erhalten Einreichungen von Antragsteller:innen über FIT-Connect. Das Empfangen von Anträgen ist auf der Seite Abruf von Einreichungen beschrieben.

Das Java-SDK setzt Details wie Validierungen und Entschlüsselung intern um, sodass Sie sich bei der Anbindung auf die Implementierung der Schnittstelle fokussieren können.

Im Folgenden wird gezeigt, wie Sie mit dem Java-SDK eine Submission von einem Zustellpunkt abrufen.

Konfiguration erstellen

Für die Implementierung eines Verwaltungsystems benötigen Sie zunächst eine Konfiguration. Diese kann über die YAML Datei config.yml, oder programmatisch über einen Builder der Klasse ApplicationConfig erstellt werden. Unter Java-SDK - Überblick ist beschrieben, wie Sie Informationen für ein Verwaltungssystem in diese Datei eintragen.

Java YAML
JWK signingKey = loadKey("/signing_key.json");
JWK decryptionKey = loadKey("/decryption_key.json");

var subscriber = SubscriberConfig.builder()
.clientId("clientId")
.clientSecret("clientSecret")
.privateDecryptionKeys(List.of(decryptionKey))
.privateSigningKey(signingKey)
.build();

var config = ApplicationConfig.builder()
.subscriberConfig(subscriber)
.activeEnvironment(TEST.getEnvironmentName())
.build();


subscriberConfig:
clientId: "clientId"
clientSecret: "clientSecret"
privateDecryptionKeyPaths: ["/decryption_key.json"]
privateSigningKeyPath: "/signing_key.json"
activeEnvironment: TEST

Die YAML Konfiguration wird anschließend mit dem ApplicationConfigLoader geladen, wie das folgende Beispiel zeigt:

var path = Path.of("/path/to/config");
ApplicationConfigLoader.loadConfigFromPath(path);

Client für Verwaltungssystem erstellen

Im nächsten Schritt wird ein SubscriberClient benötigt, der mittels der ClientFactory erzeugt werden kann.

 SubscriberClient subscriberClient = ClientFactory.createSubscriberClient(config);

Submission laden

Das Laden von Submissions erfolgt in zwei Schritten.

  • Erfragen, ob abholbereite Submissions für einen Zustellpunkt vorliegen.
    Dieser Schritt ist nicht erforderlich, wenn das Verwaltungssystem durch einen Callback darüber informiert wird, dass Submissions abholbereit sind.
  • Abholen einer bestimmten Submission.

Abholbereite Submissions erfragen

Das folgende Beispiel zeigt, wie Sie beim Zustelldienst erfragen, ob für einen Zustellpunkt (eine Destination) Submissions zur Abholung bereitstehen:

 SubscriberClient subscriberClient = ClientFactory.createSubscriberClient(config);

int offset = 0;
int limit = 100;
var destinationId = UUID.fromString("d2d43892-9d9c-4630-980a-5af341179b14");

Set<SubmissionForPickup> availableSubmissions = subscriberClient.getAvailableSubmissionsforDestination(destinationId, limit, offset);

Von der Methode getAvailableSubmissionsforDestination erhalten Sie die IDs der abholbereiten Einreichungen (siehe Beispiel oben). Mittels Paging werden über die Angabe von limit und offset Teilresultate geladen. Die im Set enthaltenen SubmissionForPickup ermöglichen den Zugriff auf destinationId, submissionId und caseId. Ohne Paging werden die ersten 500 Submissions geladen, siehe folgendes Beispiel:

 var subscriberClient = ClientFactory.createSubscriberClient(config);

var destinationId= UUID.fromString("d2d43892-9d9c-4630-980a-5af341179b14");

Set<SubmissionForPickup> availableSubmissions = subscriberClient.getAvailableSubmissionsForDestination(destinationId);

Eine Submission abrufen

Mit der Methode requestSubmission laden Sie eine abholbereite Submission (ReceivedSubmission) inklusive der Fach- und Metadaten sowie der Attachments (falls vorhanden). Sie können dieser Methode die submissionId übergeben oder das Objekt SubmissionForPickup:

// mittels submissionId
var submissionId = UUID.fromString("d2d43892-9d9c-4630-980a-5af341179b14");
ReceivedSubmission receivedSubmission = subscriberClient.requestSubmission(submissionId);
// mittels Objekt
SubmissionForPickup submissionForPickup = // abholbereite Submission
ReceivedSubmission receivedSubmission = subscriberClient.requestSubmission(submissionForPickup);

Hinweis

Das SDK prüft beim Abruf von Submission die erhaltenen Daten. Zudem prüft das SDK, ob Token und Schlüssel gültig sind. Schlägt eine Prüfung fehl, dann wird die Submission automatisch vom Verwaltungssystem zurückgewiesen. Das bedeutet, dass ein REJECT-Event an das Event-Log gesendet wird, mit der darauf folgenden Löschung der invaliden Submission.
Dieses Verhalten ist in den Umgebungen PROD, STAGE und TEST aktiv, kann jedoch über die Eigenschaft enableAutoReject in den Einstellungen des SDKs deaktiviert werden.

Zugriff auf Fach- und Metadaten

Sie können über die ReceivedSubmission auf die Fach- und Metadaten sowie auf die Attachments einer Submission zugreifen, nachdem die Submission geladen, entschlüsselt und erfolgreich validiert wurde:

 // Zugriff auf Fachdaten
String data = receivedSubmission.getDataAsString();
URI dataSchemaUri = receivedSubmission.getDataSchemaUri();
String mimeType = receivedSubmission.getDataMimeType();

// Zugriff auf Metadaten
Metadata metadata = receivedSubmission.getSubmissionMetdata();

// Zugriff auf Rückkanal
ReplyChannel replyChannel = metadata.getReplyChannel();

// Zugriff auf Attachments
for( Attachment attachment : receivedSubmission.getAttachments()){
String originalFilename = attachment.getFilename();
String attachmentMimeType = attachment.getMimeType();
// Rohdaten des Attachments als byte[]
byte[] attachmentDataAsBytes = attachment.getDataAsBytes();
// Rohdaten des Attachments als String (per default UTF-8 encoded)
String attachmentDataAsString = attachment.getDataAString();
}

// Zugriff auf IDs
UUID caseId = receivedSubmission.getCaseId();
UUID submissionId = receivedSubmission.getSubmissionId();
UUID destinationId = receivedSubmission.getDestinationId();
Hinweis für die Bidirektionale Kommunikation

Sofern Sie beabsichtigen die bidirektionale Kommunikation zu nutzen stellen Sie an dieser Stelle sicher, dass die Submission mit den Metadaten in Ihrer Anwendung gesichert werden, da hier sowohl die Verschlüsselungs-Keys als auch die zu nutzenden Prozessstandards angegeben werden. Diese Submission übergeben Sie später an die entsprechende Funktionen.

Zugriff auf große Attachments

Wenn der Sender (Onlinedienst) die Einreichung mit aktiviertem Attachment Chunking gesendet hat, kann der Empfänger auf Attachments zugreifen die aus einzelnen Fragmenten zusammengesetzt wurden (Large-Attachments). Dabei wird das resultierende Attachment im Dateisystem abgelegt, da die Daten u.U. nicht in den Hauptspeicher (RAM) passen.

Metadatenversion

Um Chunking zu nutzen, muss die Destination ein Metadatenschema in der Version >= 1.3.0 unterstützen.

Für den Zugriff auf die Datei eines großen Attachments, besitzt die Attachment Klasse zwei Methoden, die im folgenden Beispiel dargestellt sind:

// (Optionale) Prüfung ob es sich um ein großes Attachment mit Daten im Dateisystem handelt
if(attachment.isLargeAttachment()){
// Zugriff auf das File als Stream
InputStream attachmentStream = attachment.getDataAsInputStream();
// Direkter Zugriff auf den Pfad im Dateisystem
Path largeFilePath = attachment.getLargeAttachmentFilePath();
...
}else{
// In-Memory Attachment das in den RAM geladen wird
byte[] attachmentData = attachment.getDataAsBytes();
...
}
Large-Attachments als Byte-Array

Wird auf ein Large-Attachment dennoch über getDataAsBytes() zugegriffen, sollte beachtet werden, dass Byte-Arrays in Java eine max. Größe von 2 GB haben und die Daten evtl. nicht in den Speicher geladen werden können.

Dateisystem bereinigen

Um die Daten der Attachments, die im Dateisystem abgelegt wurden, zu bereinigen gibt es zwei Varianten:

Aufruf der delete()-Methode auf dem File eines Attachments
Attachment largeAttachment = ....
largeAttachment.getLargeAttachmentFilePath().toFile().delete();
Clean-up Funktion des

Hier werden alle vom SDK erzeugten Ordner und Dateien aus dem AttachmentStorage-Pfad gelöscht:

var subscriber = ClientFactory.createSubscriberClient(config);
subscriber.clearAttachmentStorage();
Nutzung von Attachment-Dateien im Filesystem

Die vom SDK erzeugten Dateien sollten nur temporär genutzt werden. Für die Sicherung und Ablage, wird empfohlen diese (bspw. ins Fachverfahren) zu verschieben.

Submission Status abrufen

Sie rufen den Status einer Submission mit der Methode getSubmissionStatus der Klasse SubscriberClient ab:

 SubscriberClient subscriberClient = ClientFactory.createSubscriberClient(config);

SubmissionForPickup submissionForPickup = ...

var destinationId = submissionForPickup.getDestinationId();
var caseId = submissionForPickup.getCaseid()
var submissionId = submissionForPickup.getSubmissionId()

Status submissionStatus = subscriberClient.getSubmissionStatus(destinationId, caseId, submissionId);

LOGGER.info("Current status for submission {} => {}", submissionId, submissionStatus.getStatus());

Das folgende Beispiel zeigt die Ausgabe des Status einer Submission, nachdem sie angelegt wurde:

Current status for submission 43cf7163-5163-4bc8-865e-be96e271ecc3 => submitted
Hinweis

Beim Statusabruf durch Verwaltungssysteme werden keine AuthenticationTags validiert. Diese sind nur auf der Onlinedienst-Seite verfügbar.

Das folgende Diagramm zeigt alle Zustandsübergänge einer Submission, vom Anlegen der Submission bis zur Abholung durch das Verwaltungssystem. Klicken Sie auf das Diagramm, um es zu vergrößern.

Status

Empfangsbestätigung

Um eine Submission zu akzeptieren oder abzulehnen, kann der Verwaltungssystem-Client entsprechende Events an das Event-Log senden.

Event Log

Weitere Details finden Sie in der Dokumentation zu Events und die Erzeugung von Security Event Tokens.

Submission akzeptieren

Nach der fachlichen Prüfung der Submission durch das Verwaltungssystem kann sie mit einem accept-submission-Event angenommen werden. Diesem Event können Sie Problems hinzufügen, die Anmerkungen ermöglichen und nicht zur Zurückweisung der Submission führen:

 SubscriberClient subscriberClient = ClientFactory.createSubscriberClient(config);
var submissionId = UUID.fromString("d2d43892-9d9c-4630-980a-5af341179b14");

// Abholen der Submission mit allen Daten
ReceivedSubmission receivedSubmission = subscriberClient.requestSubmission(submissionId);

// Akzeptieren der Submission ohne die Angabe von Problems
receivedSubmission.acceptSubmission();

// Akzeptieren der Submission mit einer Liste von Problems
receivedSubmission.acceptSubmission(List.of(new MyCustomProblem()));;
Hinweis

Nach dem Senden des accept-submission-Events wird die Submission in den Status deleted überführt und im Zustelldienst gelöscht.

Submission zurückweisen

Fällt die fachliche Prüfung des Verwaltungssystems negativ aus, wie zum Beispiel bei nicht entschlüsselbaren oder nicht schemakonformen Fachdaten, muss die Submission zurückgewiesen werden.
Die Zurückweisung erlaubt die Angabe von Problems aus der Domäne *.api.domain.model.event.problems.*. Weitere Details finden Sie unter den verfügbaren (technischen) Problemen.

 SubscriberClient subscriberClient = ClientFactory.createSubscriberClient(config);
var submissionId = UUID.fromString("d2d43892-9d9c-4630-980a-5af341179b14");

// Abholen der Submission mit allen Daten
ReceivedSubmission receivedSubmission = subscriberClient.requestSubmission(submissionId);

// Senden der Zurückweisung mit einer Liste von Problemen
receivedSubmission.rejectSubmission(List.of(new DataSchemaViolation(), new MyCustomProblem("Angegebene Stadt existiert nicht")));

Nach Senden des reject-submission-Events wird die Submission in den Status deleted überführt und im Zustelldienst gelöscht.

Submission direkt zurückweisen

Wenn Sie eine oder mehrere Submissions direkt zurückweisen wollen, ohne zuvor alle Daten zu laden, dann können Sie diese Submissions auch über den SubscriberClient zurückweisen:

 SubscriberClient subscriberClient = ClientFactory.createSubscriberClient(config);
var destinationId = UUID.fromString("d2d43892-9d9c-4630-980a-5af341179b14");

Set<SubmissionForPickup> submissions = subscriberClient.getAvailableSubmissionsForDestination(destinationId);

// direkte Zurückweisung aller SubmissionForPickup ohne Laden weiterer Daten
submissions.forEach(submission -> subscriberClient.rejectSubmission(submission, List.of(new TechnicalProblem())))

Bidirektionale Kommunikation

FIT-Connect ermöglicht einen Dialog zwischen Onlinedienst und Verwaltungssystem, sodass Onlinedienst und Verwaltungssystem direkt Nachrichten miteinander austauschen können. Dieser Dialog wird Bidirektionale Kommunikation (BiDiKo) genannt.

Die Seite Onlinedienst beschreibt die bidirektionale Kommunikation und definiert wichtige Begriffe, wie Replys (Antworten des Verwaltungssystems auf Einreichungen von einem Onlinedienst).

Verwaltungssystem sendet Antwort über FIT-Connect

FIT-Connect ermöglicht einem Verwaltungssystem, eine Antwort (Reply) zu einer Einreichung an den Onlinedienst zurückzusenden. Der Onlinedienst kann auf die Antwort reagieren, indem er eine neue Einreichung an das Verwaltungssystem über FIT-Connect sendet.

Auf eine Submission antworten

Sie senden eine Antwort zu einer Einreichung (Submission) zurück, indem Sie ein SendableReply von dieser ReceivedSubmission erzeugen (siehe folgendes Beispiel). Alle Daten der erhaltenen Submission werden übernommen. Die Fachdaten und Attachments können im Reply jedoch neu gesetzt werden.

Anschließend senden Sie die Antwort (Reply) mit der Methode SubscriberClient.sendReply(...) an das Verwaltungssystem über FIT-Connect zurück:

 ReceivedSubmission receivedSubmission = subscriberClient.requestSubmission(submissionId);

SendableReply sendableReply = SendableReply.from(receivedSubmission)
.setJsonData(getReplyJsonData(), URI.create("https://schema.fitko.de/fim/s00000114_1.1.schema.json"))
.addAttachment(Attachment.fromPath(Path.of("fitconnect/data/reply-attachment.txt"), "application/pdf"))
.build();

SentReply sentReply = subscriberClient.sendReply(sendableReply);
Voraussetzung

Das Zurücksenden einer Antwort über FIT-Connect ist nur dann möglich, wenn für die Submission, auf die geantwortet werden soll, FIT-Connect als Rückkanal gesetzt ist.

Hinweis zur aktuellsten Submission

Um sicherzustellen das der neueste Verschlüsselungsschlüssel eines Case abgerufen wird, sollten zunächst alle Submissions eines Case geladen werden und nach dem submittedtAt Zeitstempel der ReceivedSubmisssion sortiert werden. Die ReceivedSubmission kann hierzu automatisch sortiert werden, da sie intern das Comparable-Interface implementiert, welches bereits den Zeitstempel vergleicht.

Status einer Antwort abrufen

Sie erfragen den Status einer gesendeten Antwort (sentReply), indem Sie die Methode getReplyStatus der Klasse SubscriberClient aufrufen:

 Status replyStatus = subscriberClient.getReplyStatus(sentReply);
assertThat(replyStatus.getStatus(), is(EventState.SUBMITTED));

Callbacks validieren

Beim Empfang von Callbacks sollten Sie prüfen, ob die empfangenen Daten gültig sind, um unautorisierte Zugriffe auf Geschäftsprozesse und Nutzerdaten zu verhindern. Die für die Validierung notwendigen Daten befinden sich innerhalb des empfangenen HTTP-Request. FIT-Connect nutzt das HMAC-Verfahren, um die Gültigkeit des Aufrufs zu überprüfen.

Hierfür bietet das SDK die Methode validateCallback der Klasse SubscriberClient:

 SubscriberClient subscriberClient = ClientFactory.createSubscriberClient(config);

ValidationResult validationResult = subscriberClient.validateCallback("hmac", 0L, "body", "secret");

if(validationResult.hasError()){
LOGGER.error(validationresult.getError().getMessage());
}
Hinweis

Weitere Details zur Funktionsweise von Callbacks finden Sie hier.