Tutorial

IFS-Logo Diese Seite ist ein Teil der IsyFact-Standards. Alle Inhalte der Seite, insbesondere Texte und Grafiken, sind urheberrechtlich geschützt. Alle urheberrechtlichen Nutzungs- und Verwertungsrechte liegen beim Bundesverwaltungsamt.

Creative Commons Namensnennung Die Nutzung ist unter den Lizenzbedingungen der Creative Commons Namensnennung 4.0 International gestattet.

1. Einleitung

Dieses Dokument dient als Einstieg in die technischen Grundlagen der IsyFact. Es enthält in Kurzform die wesentlichen Designvorgaben und beschreibt, wie einzelne Aspekte in Anwendungen umzusetzen sind, die gemäß der Referenzarchitektur der IsyFact gebaut werden. Das Dokument unterstützt damit Entwickler und technische Chefdesigner bei der Konstruktion und Realisierung von Anwendungen einer zur IsyFact konformen Anwendungslandschaft. Im Sinne einer Referenz enthält es jedoch nicht alle Details der zugrunde liegenden Konzepte. Der Fokus liegt darauf, einen schnellen Überblick über die einzelnen Themen zu geben und die wichtigsten Realisierungsaufgaben zusammenfassend darzustellen.

Zunächst beschreibt das Kapitel Bezug IsyFact, wie sich die IsyFact in Entwicklungsprojekte einbinden lässt. Danach beleuchten die Kapitel Datenhaltung , Fachkomponenten der Anwendung und Anwendungsnutzung jeweils einzelne Kernthemen der Anwendungsentwicklung. Kapitel Querschnitt fasst alle Querschnittsthemen zusammen. Jedes Teilkapitel beginnt in der Regel mit der Auflistung der wichtigsten Designvorgaben und einem Klassendiagramm. Es folgt eine Realisierungsanleitung, die alle wesentlichen Schritte zur Umsetzung in Kurzform enthält.

2. Bezug und Nutzung der IsyFact

Alle Bibliotheken der IsyFact stehen über Maven Central zum Download bereit. Zur Nutzung der Bibliotheken in der Anwendungsentwicklung steht ein zentrales BOM (Bill Of Materials) zur Verfügung, das Teil der Maven-Konfiguration (pom.xml) wird:

Listing 1. Einbindung des IsyFact-BOM
<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>de.bund.bva.isyfact</groupId>
            <artifactId>isyfact-bom</artifactId>
            <version>3.3.x</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>

Somit kann zentral eine zu nutzende Version der IsyFact festgelegt werden. Diese legt ebenfalls die Versionen aller Drittprodukte fest, die im Produktkatalog der IsyFact enthalten sind. Aktualisierungen geschehen ebenfalls zentral, durch die Erhöhung der Versionsnummer des IsyFact-BOM.

Durch die Nutzung des IsyFact-BOM ist es nicht mehr notwendig, die IsyFact-Bibliotheken mit einzelnen Versionsnummern einzubinden. Die Versionsnummer ermittelt Maven zentral über das BOM. Es reicht also folgender Abschnitt, um eine Bibliothek einzubinden:

Listing 2. Einbindung einer IsyFact-Bibliothek
<dependencies>
    ...
    <dependency>
        <groupId>de.bund.bva.isyfact</groupId>
        <artifactId>isy-logging</artifactId>
    </dependency>
    ...
</dependencies>

3. Datenhaltung

In diesem Kapitel wird die Implementierung der Datenhaltung einer Anwendung beschrieben. Die Datenhaltung besteht im Wesentlichen aus den Entitäten (Entity) und den zugehörigen Data Access Objects (DAOs). Alle Konzepte und Vorgaben zum Thema Persistenz und Datenzugriff stehen im Detailkonzept Komponente Datenzugriff sowie im Konzept JPA/Hibernate.

3.1. Designvorgaben

  • Der eigentliche Datenbankzugriff wird über die Java Persistence API (JPA) gekapselt. Als Implementierung für die JPA wird Hibernate verwendet.

  • Das Datenbank-Mapping wird über Annotation in den Klassen der Entitäten festgelegt.

  • Der Zugriff auf Entitäten erfolgt immer über DAOs oder durch die Traversierung des persistenten Datenmodells.

  • DAOs stellen Zugriffsmethoden (Suchen, Schreiben, Löschen…​) für genau eine Entität bereit.

  • Datenbank-Queries werden im Normalfall aus den Methodennamen generiert. Sonst werden sie per @Query-Annotation an der Methode beschrieben.

  • Entitäten werden entweder von genau einer fachlichen Komponente oder querschnittlich von der Komponente „Basisdaten“ verwaltet.

  • Der Datenzugriff erfolgt entweder über die Komponenten-Schnittstelle oder im Fall der Basisdaten direkt über die Basisdaten-DAOs.

  • Für persistente Entitäten, die über eine Komponentenschnittstelle angeboten werden, werden eigene Schnittstellenobjekte definiert, die per Deep-Copy gefüllt werden. Hierfür wird ein Bean-Mapper verwendet. Innerhalb einer Teilanwendung dürfen persistente Entitäten allerdings über Komponentengrenzen hinweg genutzt werden.

  • DAOs und Entitäten werden in einer festgelegten Paketstruktur abgelegt.

  • Die Transaktionssteuerung wird per AOP in der Service-Schicht durchgeführt (siehe Kapitel Anbieten von Service-Schnittstellen).

    Aspect-Oriented Programming (AOP) ist ein Programmierparadigma, das anstrebt, verschiedene logische Aspekte eines Programmes getrennt voneinander zu entwerfen, zu entwickeln und zu testen. Die getrennt entwickelten Aspekte werden dann zur endgültigen Anwendung zusammengefügt. * Der Primärschlüssel einer Entität besteht aus genau einem Attribut. Besteht der fachliche Schlüssel der Entität aus genau einem Attribut, so wird er auch als Primärschlüssel verwendet. Ansonsten wird ein künstlicher technischer Primärschlüssel verwendet.

3.2. Klassendesign

Datenhaltung
Abbildung 1. Klassendesign für die Datenhaltung
Tabelle 1. Klassenbeschreibung für die Datenhaltung

AuskunftImpl

AuskunftImpl ist die Implementierung der Komponente Auskunft (Anwendungskern). Die Komponente verwendet die DAOs zum Zugriff auf ihre Daten. Während die DAOs die eigentlichen Entitätstypen anbieten, liefert die Komponente Auskunft nur nicht persistente Schnittstellenobjekte auf ihre Daten.

RegisterEintragDao

DAOs kapseln den Datenbankzugriff für spezifische Entitätstypen. Sie stellen Methoden zum Suchen, Anlegen und Löschen dieser Typen zur Verfügung. Zur Durchführung der Datenbank-Queries benötigt das DAO den EntityManager. Dieser wird von Spring bereitgestellt.

RegisterEintrag

Implementierungsklasse für Entitäten vom Typ RegisterEintrag. Enthält Getter- und Setter-Methoden für alle Attribute.

RegisterEintragDaten

Nicht persistentes Schnittstellenobjekt, das die Daten des RegisterEintrags enthält. Wird als Deep-Copy durch Bean-Mapper erzeugt.

Im Normalfall verwenden Komponenten die Daten anderer Komponenten über deren Schnittstelle. Der direkte Zugriff auf die DAOs ist verboten.

Entitäten, die von mehreren Anwendungskomponenten verwendet werden, bietet die Komponente Basisdaten an. Die Komponente Basisdaten ist keine vollständige Komponente, sie bietet keine Schnittstellen an. Ausnahmsweise verwenden Komponenten stattdessen direkt die zugehörigen DAOs der Basisdaten. Dieser Fall ist auch in Abbildung 1 dargestellt. Weitere Details können der IsyFact Referenzarchitektur entnommen werden.

3.3. Realisierung

Zur Realisierung der Datenhaltung müssen folgende Aktivitäten durchgeführt werden.

3.3.1. Anlegen des Datenbankschemas

Das Datenbankschema muss angelegt werden. Dazu werden die benötigten DDL-Anweisungen, wie in Versionierung von Datenbankschemas beschrieben, in einem Verzeichnis abgelegt.

Das initiale Datenmodell kann über das Tool hbm2ddl erzeugt werden. Dieses muss anschließend noch bearbeitet werden.

hbm2ddl ist Teil der von Hibernate bereitgestellten Werkzeuge. Nutzungsdokumentation unter: Hibernate Toolset Guide

3.3.2. Einbinden der Bibliotheken

Die benötigten Bibliotheken müssen als Abhängigkeiten in die Maven-Konfiguration (pom.xml) aufgenommen werden:

Listing 3. Einbindung der Bibliotheken für das Anbieten einer Datenhaltung
<dependencies>
    ...
    <dependency>
        <groupId>de.bund.bva.isyfact</groupId>
        <artifactId>isy-persistence</artifactId>
    </dependency>
    ...
</dependencies>

3.3.3. Implementierung der Entitätsklassen und DAOs

Die Entitätsklassen und Schnittstellen-Klassen müssen implementiert werden. In den Entitätsklassen müssen die Mapping-Informationen für JPA als Annotationen eingetragen werden. Die Implementierung der DAOs wird automatisch generiert.

3.3.4. Implementierung von Schnittstellen-Klassen

Schnittstellen-Klassen dienen als eine nur Lese-Sicht auf persistente Entitäten. Dieses wird benötigt, wenn Komponenten persistente Entitäten über ihre Schnittstelle herausgeben, um zu verhindern, dass andere Komponenten diese Daten ändern.

Schnittstellen-Klassen enthalten alle Attribute, die auch ihre persistenten Gegenstücke besitzen. Zusätzlich besitzen sie Getter-/Settermethoden für alle Attribute.

Die Schnittstellen-Objekte werden per Deep-Copy mittels eines Bean-Mappers erzeugt und dem Aufrufer außerhalb der Teilanwendung zurückgeliefert. So stehen dem Aufrufer alle Informationen zur Verfügung, es ist ihm aber nicht möglich, Änderungen zu persistieren. Damit ist die Datenhoheit der Komponente gewahrt.

Im Folgenden ist ein beispielhaftes Mapping zu sehen:

Listing 4. Beispielhaftes Bean-Mapping
/* Bean-Mapper */
protected MapperFacade mapper;
// Entität mappen
RegisterEintragDaten daten = mapper.map(registerEintrag, RegisterEintragDaten.class);

4. Fachkomponenten der Anwendung

In diesem Kapitel wird die Realisierung von Fachkomponenten beschrieben.

4.1. Designvorgaben

  • Alle Komponenten definieren ihre Schnittstelle über ein Java-Interface. Eine Ausnahme bildet die Komponente Basisdaten. Diese Komponente verwaltet gemeinsam genutzte Daten und bietet keine eigene Schnittstelle an. Der Zugriff erfolgt hier direkt über die DAOs (siehe Kapitel Klassendesign).

  • Komponenten bieten an ihrer Schnittstelle eine Nur-Lese-Sicht auf ihre Daten an. Für jeden Entitätstyp wird eine nicht-persistente Schnittstellenklasse erstellt. Die Komponentenschnittstelle wird von einer Java-Klasse implementiert. Diese Klasse kann die Anwendungsfälle im einfachen Fall direkt implementieren oder an Anwendungsfall-Klassen delegieren.

  • Die interne Strukturierung von Komponenten ist nicht im Detail vorgeben. Für fachliche Komponenten wird eine Basisimplementierung in IsyFact Referenzarchitektur beschrieben.

4.2. Klassendesign

Fachliche Komponente
Abbildung 2. Klassendesign für Fachkomponenten
Tabelle 2. Klassenbeschreibung für Komponenten Datenhaltung

Auskunft

Interfaces zur Definition der Schnittstelle der Komponente "Auskunft".
Zu beachten ist, dass über die Schnittstelle keine Entitäten der Komponente herausgegeben werden. Es darf immer nur eine Nur-Lese-Sicht (nicht-persistente Schnittstellen-Objekte) herausgegeben werden.
Die Umwandlung der internen (RegisterEintrag) auf die externe Sicht erfolgt per Bean-Mapper.

AuskunftImpl

Implementierung der Komponente Auskunft. Diese Klasse wird als Spring-Bean konfiguriert. Weitere benötigte Komponenten (Spring-Beans) werden dieser Komponente per Spring-Dependency-Injection bekannt gemacht. Alle weiteren Klassen der Komponente, z.B. AWF-Klassen werden in der AuskunftImpl "normal" instanziiert, und die benötigten Referenzen übergeben.

AwfLeseGesamtBestand

Beispielklasse zur Implementierung eines Anwendungsfalls. Diese Klassen werden explizit instanziiert, also nicht als Spring-Bean konfiguriert. Falls ein Anwendungsfall weitere Komponenten (Konfiguration, Regelwerk) etc. benötigt, werden diese durch die instanziierende Impl-Klasse übergeben.

RegisterEintrag

Persistente Entität für Register-Einträge.

RegisterEintragDaten

Nur-Lese-Sicht auf Register-Einträge (siehe Kapitel Implementierung von Schnittstellen-Klassen).

4.3. Package-Struktur

  • Die Realisierung der Komponenten-Schnittstelle erfolgt im Package
    <organisation>.<domäne>.<system>.core.<komponente>

    Für das Bundesverwaltungsamt ist dies z.B. de.bund.bva
  • Die Realisierung der Komponenten-Implementierung erfolgt im Package
    <organisation>.<domäne>.<system>.core.<komponente>.impl.*

  • Die nicht-persistenten Schnittstellen-Klassen werden im Package
    <organisation>.<domäne>.<system>.core.<komponente>.ausgabedaten.*
    implementiert.

4.4. Realisierung

  • Die Implementierungsklassen und Interfaces der Komponente werden implementiert.

  • Die Komponente mit @Component bzw. mit einer passenden Spezialisierung annotiert, damit sie von Spring als Bean konfiguriert wird.

  • Je nach Bedarf wird die Komponente anderen Komponenten per Dependency Injection bekannt gemacht.

5. Anwendungsnutzung

In diesem Kapitel wird die Realisierung von verschiedenen, technischen Zugangswegen zum Anwendungskern beschrieben, mit Ausnahme des GUI-Zugangs. Das Thema umfasst das Anbieten von internen Service-Schnittstellen per HTTP Invoker, das Nutzen derselben und die Nutzung des Anwendungskerns im Rahmen der Batch-Verarbeitung.

RAIT
Abbildung 3. Referenzarchitektur eines IT-Systems

5.1. Anbieten von Service-Schnittstellen

Deprecation

Dieser Teil der Dokumentation ist veraltet und wird in einem zukünftigen Release entfernt. Die Inhalte sollten zur Entwicklung neuer Anwendungen nicht mehr berücksichtigt werden.

Anmerkung zur Deprecation

Der ab IF 3.0 eingesetzte neue Baustein isy-security wird keine HTTPInvoker Schnittstellen mehr nativ unterstützen und daher sollen diese ab IF 3.0 nicht mehr verwendet werden.

Dieser Abschnitt beschreibt die Realisierung von HTTP Invoker Schnittstellen (siehe Spring). HTTP Invoker Schnittstellen sind interne Service-Schnittstellen, die innerhalb der Anwendungslandschaft durch andere Anwendungen genutzt werden dürfen.

Ab IsyFact 2.0 ist die Verwendung von REST-Schnittstellen erlaubt. HTTP Invoker wird in folgenden Releases (IsyFact 2.x) als Schnittstellenformat abgelöst. Die Verwendung von REST-Schnittstellen wird einem gesonderten Konzept erläutert.

Ab IsyFact 3.0 wird die Verwendung von HTTPInvoker Schnittstellen nicht mehr empfohlen und wird in zukünftigen Versionen nicht mehr unterstützt werden.

Extern verfügbare Services sind durch WebService-Schnittstellen anzubieten, über einen ServiceGateway.

5.1.1. Designvorgaben

  • Interne Services werden per Spring HTTP Invoker angeboten.

  • Es werden keine Komponenten des Anwendungskerns extern verfügbar gemacht: Es wird stets eine eigene Service-Schicht implementiert. Dazu gehört auch die Definition einer Service-Schnittstelle als Java-Interface (RemoteBean).

  • Jede Service-Methode erhält einen zusätzlichen Parameter AufrufKontext. Im Aufrufkontext werden Informationen zum Aufrufer (Name, Behördenkennzeichen, Rollen…) übermittelt. Die Implementierungen verschiedener Aufrufkontext-Transportobjekte sind in der Bibliothek isy-serviceapi-sst enthalten.

  • Die Implementierung der Service-Schnittstelle wird in eine Exception-Fassade und die eigentliche Service-Implementierung aufgeteilt.

  • In der Service-Schnittstelle werden nur Transport-Exceptions und Transportobjekte verwendet. Die Umwandlung der internen Exceptions und Entitäten auf Transport-Exceptions und -Objekte erfolgt in der Service-Schicht.

  • Listen von Objekten in Ein- und Ausgabeparametern werden als Arrays übertragen. Andere Collection-Typen sind nicht erlaubt.

  • Beim Kompilieren der Schnittstellenprojekte muss auf die Java-Version geachtet werden. Die Java-Version darf nicht neuer sein, als diejenige des Nutzers. Gegebenenfalls muss die Schnittstelle auf eine ältere Version kompiliert werden.

5.1.2. Package-Struktur

  • Schnittstellen werden versioniert. Die Versionsnummer wird dreistellig im Package-Namen der Service-Schnittstelle angegeben. Beispiel: Die Version 1.0.0 einer generischen Schnittstelle einer generischen Anwendung, wird in den folgenden Packages implementiert:
    de.bund.bva.<anwendung>.<schnittstelle>.httpinvoker.v1_0_0.*

  • Interfaces, Transport-Exceptions und Transportobjekte werden im Package
    <organisation>.<domäne>.<system>.service.httpinvoker.vX_Y_Z
    implementiert

    Das sind genau die Inhalte, die im eigenen Projekt <system>-httpinvoker-sst implementiert werden.
  • Die Implementierung der Service-Schnittstelle erfolgt im Package
    <organisation>.<domäne>.<system>.service.httpinvoker.vX_Y_Z.impl.

5.1.3. Klassendesign

KDServiceSS
Abbildung 4. Klassendesign für HTTP Invoker Service-Schnittstellen
Tabelle 3. Klassenbeschreibung für Service-Schnittstellen

AuskunftRemoteBean

Externes Interface für den Zugriff auf die Auskunft-Komponente per HTTP Invoker. Bei Nutzung einer Service-Schnittstelle generiert Spring auf Basis dieses Interfaces einen Proxy für den Remote-Zugriff.
Die Methoden dieser Komponente verwenden ausschließlich Transportobjekte und -Exceptions.
Die Überwachung der Service-Aufrufe (siehe Kapitel Überwachung) wird als Aspekt der RemoteBean konfiguriert.

AuskunftToException

Transport-Exception der Auskunft. Jede Komponente darf ausschließlich Transport-Exceptions an ihrer Service-Schnittstelle werfen. Details sind in Konzept Fehlerbehandlung nachzulesen.

AufrufKontextTo

AufrufKontext der Service-Utilities mit den Informationen zum Aufrufer (Name, Passwort, Rollen…).

RegisterEintragTo

Transportobjekt für Register-Eintrag-Entitäten.

AuskunftExceptionFassade

Die Klasse AuskunftExceptionFassade implementiert das AuskunftRemoteBean-Interface. Die Exception-Fassade erhält damit alle Aufrufe der Auskunft-Service-Schnittstelle. Diese werden an die Auskunft-Service-Implementierung (AuskunftServiceImpl) delegiert. Die Aufgabe der Exception-Fassaden ist das Exception-Handling und -Mapping durchzuführen.
Wichtig ist, einen Catch-Throwable-Block um den Aufruf der AuskunftService-Implementierung zu machen, um sicherzustellen, dass alle auftretenden Fehler gefangen werden. Die Implementierung der Fehlerbehandlung wird im Detail in Konzept Fehlerbehandlung beschrieben.
In der Exception-Fassade muss die Correlation-ID aus dem AufrufKontext in den Logging-Kontext gesetzt werden (siehe Kapitel Logging).

AuskunftService

Internes Interface für den Auskunft-Service. Diese Schnittstelle verwendet Transportobjekte aber noch die internen Exceptions. Diese werden erst von der Exception-Fassade auf die eigentlichen Exceptions der AuskunftRemoteBean umgewandelt.

AuskunftServiceImpl

Implementierung des AuskunftService. In Service-Implementierung müssen die folgenden Aktivitäten durchgeführt werden:

  • Berechtigungsprüfung

  • Mappen der eingehenden Daten

  • Aufrufen des Anwendungskerns (Auskunft)

  • Mappen der ausgehenden Daten

Das Mappen der Daten wird mit einem Bean Mapper durchgeführt.

Dies geschieht automatisiert, ohne dass man Mapping-Informationen hinterlegen muss. Grund hierfür ist die strukturelle Gleichheit der Objekte des Anwendungskerns und der Service-Schicht. Dadurch ist der Bean Mapper in der Lage diese Objekte generisch zu übersetzen.

In den Service-Implementierungen wird außerdem die Transaktionssteuerung durchgeführt. Diese wird per Spring-AOP über Annotations konfiguriert (siehe Kapitel Datenhaltung).

5.1.4. Realisierung

Zur Realisierung einer Service-Schnittstelle müssen einige Aktivitäten ausgeführt werden. Diese werden im Folgenden beschrieben.

5.1.4.1. Anlegen des Schnittstellenprojekts

Das neue Projekt <system>-httpinvoker-sst muss angelegt werden. Dazu wird eine neue pom.xml angelegt. Wichtig ist, dass darin die Compiler-Version so festgelegt wird, wie es im Produktkatalog vorgegeben ist.

Das Projekt muss ein Jar erzeugen, das von anderen Systemen zur Nutzung der Service-Schnittstelle benötigt wird. In der Pom-Datei muss konfiguriert werden, dass das Jar in das Verzeichnis repository-deploy (Deployment-Repository) deployt wird.

Das Schnittstellen-Projekt erhält dieselbe Group-ID wie das eigentliche Anwendungsprojekt. Die Artifact-ID ist <system>-httpinvoker-sst.

5.1.4.2. Realisierung der „externen“ Service-Schnittstelle

Das RemoteBean-Interface, die Transportobjekte und -Exceptions müssen im Schnittstellen-Projekt angelegt werden.

5.1.4.3. Realisierung der Service-Implementierung

Im Projekt der eigentlichen Anwendung müssen die Exception-Fassade, das Service-Interface (z.B. AuskunftService) und die Implementierung dieses Interfaces angelegt werden.

Im Rahmen der Implementierung muss ggf. die Bean-Mapping-Konfiguration für die Transformation der Transport- auf die Entitätsobjekte angelegt werden. Der Bean Mapper wird als Spring-Bean konfiguriert. Dabei werden die zuvor angelegten Mapping-Dateien im Mapper konfiguriert.

Die Exception-Fassade und die Service-Implementierung werden als Spring-Beans konfiguriert. Die Exception-Fassade erhält eine Referenz auf die Service-Implementierung per Dependency Injection. Genauso erhält die Service-Implementierung eine Referenz auf den Bean Mapper per Dependency Injection.

Vor der Exception-Fassade wird mithilfe der Annotation @StelltLoggingKontextBereit die mit dem Aufrufkontext mitkommende Correlation-Id für das Logging registriert.

An den Methoden der Service-Implementierung werden die Annotationen @StelltAufrufKontextBereit und @Gesichert gemäß Nutzungsvorgaben Sicherheit verwendet, um den Zugriff auf die Service-Methode zu autorisieren.

5.1.4.4. Konfigurieren der Service-Schnittstelle

In der Konfigurationsklasse der Service-Schicht wird die HTTP Invoker Konfiguration der Service-Schnittstelle durchgeführt. Dazu werden das Remote-Bean-Interface und die zugehörige Implementierung in Form der Exception-Fassade als Service konfiguriert Listing 5. Der Bean-Name ist für die URL, unter welcher der Service erreichbar sein wird, wichtig.

Listing 5. Konfiguration von Remote Bean und Exception Fassade als Service
@Configuration
public class ServiceConfiguration {

    @Bean("/AuskunftBean_v1_0")
    public IsyHttpInvokerServiceExporter auskunftService(AuskunftExceptionFassade auskunftFassade) {
        IsyHttpInvokerServiceExporter exporter = new IsyHttpInvokerServiceExporter();
        exporter.setService(auskunftFassade);
        exporter.setServiceInterface(AuskunftRemoteBean.class);
        return exporter;
    }
}

IsyHttpInvokerServiceExporter ist eine Erweiterung von HttpInvokerServiceExporter und deaktiviert standardmäßig die Verwendung von Proxy-Klassen.

5.1.4.5. Einbinden der benötigten Bibliotheken
5.1.4.5.1. Bibliotheken für das Service-Schnittstellen-Projekt

Das Projekt der Service-Schnittstelle benötigt die in Listing 6 aufgelisteten Bibliotheken:

Listing 6. Einbindung der Bibliotheken für das Service-Schnittstellen-Projekt
<dependencies>
    ...
    <dependency>
        <groupId>de.bund.bva.isyfact</groupId>
        <artifactId>isy-exception-sst</artifactId>
    </dependency>
    <dependency>
        <groupId>de.bund.bva.isyfact</groupId>
        <artifactId>isy-serviceapi-sst</artifactId>
    </dependency>
    ...
</dependencies>
5.1.4.5.2. Bibliotheken für die Implementierung der Service-Schnittstelle

In die Build-Konfiguration des Hauptprojekts des Anwendungssystems müssen folgende Bibliotheken aufgenommen werden:

Listing 7. Einbindung der Bibliotheken für das Anbieten von Service-Schnittstellen
<dependencies>
    ...
    <dependency>
        <groupId>{organisation}.{domäne}.{system}</groupId>
        <artifactId>{systemname}-httpinvoker-sst</artifactId>
    </dependency>
    <dependency>
        <groupId>de.bund.bva.isyfact</groupId>
        <artifactId>isy-exception-core</artifactId>
    </dependency>
    <dependency>
        <groupId>de.bund.bva.isyfact</groupId>
        <artifactId>isy-serviceapi-core</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
        <groupId>ma.glasnost.orika</groupId>
        <artifactId>orika-core</artifactId>
    </dependency>
    ...
</dependencies>

<systemname>-httpinvoker-sst fügt das Schnittstellen-Projekt als Abhängigkeit hinzu.

Die verwendete Version von Orika ist dem Produktkatalog zu entnehmen.

5.2. Nutzen von Service-Schnittstellen

Deprecation

Dieser Teil der Dokumentation ist veraltet und wird in einem zukünftigen Release entfernt. Die Inhalte sollten zur Entwicklung neuer Anwendungen nicht mehr berücksichtigt werden.

Anmerkung zur Deprecation

Ab der IF 3.0 ist der HTTP-Invoker deprecated und soll daher nicht mehr verwendet werden. Der Nutzung von Service-Schnittstellen soll über REST-Aufrufe erfolgen. Die Verwendung von REST-Schnittstellen wird einem gesonderten Konzept erläutert.

Dieser Abschnitt beschreibt, wie Service-Schnittstellen genutzt, d.h. aufgerufen werden können.

5.2.1. Designvorgaben

Die genutzte Schnittstelle soll vom eigenen Anwendungskern entkoppelt werden. D.h. im eigenen Anwendungskern werden keine Exceptions oder Transportobjekte der genutzten Schnittstelle verwendet. Dazu wird ein Wrapper um die Schnittstelle implementiert.

5.2.2. Klassendesign

implClntAd
Abbildung 5. Beispiel für die Implementierung eines Client-Adapters

Zum Zugriff auf den Service wird im Normalfall ein Adapter im Client implementiert (AuskunftAdapter). Dieser Adapter entkoppelt den Anwendungskern des Clients vom Service.

Im Adapter wird im Wesentlichen eine Wrapper-Klasse (AuskunftWrapper) implementiert. Diese führt das Mapping der Exceptions und der Daten durch. Der Adapter implementiert im Beispiel ein eigenes Auskunft-Interface für die Nutzung durch die Client-Anwendung.

Für die Remote Zugriffe wird der HttpInvokerProxy benutzt. Dieser wird automatisch von Spring erzeugt. Er bietet das RemoteBean-Interface auf Client-Seite an und sorgt dafür, dass Aufrufe per HTTP Invoker an den Service weitergereicht werden.

5.2.3. Realisierung

5.2.3.1. Einbinden der Schnittstellen-Bibliothek

Zur Realisierung wird die Bibliothek mit der zu nutzenden Service-Schnittstelle benötigt. Dieses befindet sich im Deployment-Repository der zu nutzenden Anwendung. Das Jar wird in das eigene Projekt-Repository kopiert und via Maven eingebunden.

Zusätzlich müssen die HTTP Invoker Bibliotheken von Spring eingebunden werden. Eine vollständige Liste zeigt Listing 8.

Listing 8. Einbindung der Bibliotheken zur Nutzung von Service-Schnittstellen
<dependencies>
    ...
    <dependency>
        <groupId>{organisation}.{domäne}.{system}</groupId>
        <artifactId>{systemname}-httpinvoker-sst</artifactId>
    </dependency>
    <dependency>
        <groupId>de.bund.bva.isyfact</groupId>
        <artifactId>isy-serviceapi-core</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    ...
</dependencies>

{systemname}-httpinvoker-sst fügt das Schnittstellen-Projekt der zu nutzenden Schnittstelle als Abhängigkeit hinzu.

5.2.3.2. Durchführen der Konfiguration

Spring erzeugt anhand des Service-Interfaces HTTP Invoker Proxies, die den eigentlichen Aufruf durchführen. Diese Proxies werden als Spring-Bean konfiguriert:

Listing 9. Proxy-Konfiguration
@Configuration
public class ServiceConfig {
    @Bean
    public HttpInvokerProxyFactoryBean invoker(ConfigProperties properties) {
        HttpInvokerProxyFactoryBean invoker = new HttpInvokerProxyFactoryBean();
        invoker.setServiceUrl(properties.getServiceUrl());
        invoker.setServiceInterface(BeispielServiceRemoteBean.class);
        return invoker;
    }
}

Auf der Bean können alle Methoden des Interfaces serviceInterface aufgerufen werden, der Aufruf erfolgt dann automatisch per HTTP Invoker gegen das in serviceUrl konfigurierte Ziel-System.

Die URL wird als betriebliche Konfiguration in application.properties ausgelagert und durch eine @ConfigurationProperties-Klasse von Spring Boot gesetzt.
5.2.3.3. Erweiterung um die Aufrufwiederholung mittels Service Utilities

Die in diesem Kapitel aufgeführte Konfiguration eines aufzurufenden Services kann durch die Verwendung einer Aufruf-Wiederholungsimplementierung erweitert werden, so dass Aufrufe bei Timeouts wiederholt werden. Dies ist nur notwendig, sofern eine Aufrufwiederholung eine Anforderung an die Anwendung ist. Für die Aufrufwiederholung ist lediglich die Spring-Konfiguration des Proxies anzupassen:

Listing 10. Konfiguration der Service-API mit Aufruf-Wiederholungen
@Configuration
public class ServiceConfig {
    @Bean
    public HttpInvokerProxyFactoryBean invoker(ServiceConfigProperties properties, HttpInvokerRequestExecutor executor) {
        HttpInvokerProxyFactoryBean invoker = new HttpInvokerProxyFactoryBean();
        invoker.setServiceUrl(properties.getServiceUrl());
        invoker.setServiceInterface(BeispielServiceRemoteBean.class);
        return invoker;
    }

    @Bean
    public TimeoutWiederholungHttpInvokerRequestExecutor executor(ServiceConfigProperties properties) {
        TimeoutWiederholungHttpInvokerRequestExecutor executor = new TimeoutWiederholungHttpInvokerRequestExecutor();
        executor.setAnzahlWiederholungen(properties.getWiederholungen());
        executor.setTimeout(properties.getTimeout());
        return executor;
    }

Auf der Bean executor sind die anzahlWiederholungen und der timeout konfiguriert. Dieser RequestExecutor erweitert den Standard-RequestExecutor von Spring um die Möglichkeit Timeouts zu definieren und eine konfigurierte Anzahl an Aufruf-Wiederholungen durchzuführen. Dieser RequestExecutor ist der Spring-HttpInvokerProxyFactoryBean bekannt zu machen.

5.2.3.4. Implementierung des Wrappers

Zur Entkopplung des eigenen Anwendungskerns von der Schnittstelle wird ein Wrapper für die Schnittstelle implementiert. Der Wrapper führt das Mapping der internen Datenobjekte auf die Transportobjekte durch. Dieses kann bei Bedarf mit einem Bean Mapper gemacht werden.

Zusätzlich führt der Wrapper das Exception-Handling durch. Der Wrapper kann auftretende Exceptions in eigene Exceptions umwandeln (Exception-Chaining) oder explizit behandeln.

5.3. Batch-Verarbeitung

In diesem Kapitel wird die Implementierung von Batches zu einer Anwendung beschrieben.

5.3.1. Designvorgaben

  • Die Batch-Verarbeitung verwendet den Anwendungskern der zugehörigen Anwendung. Der Anwendungskern ist Teil des Batch-Deployments, d.h. der Code ist sowohl Teil der Server-Anwendung als auch der Batch-Anwendung in Bezug auf Deploymenteinheiten.

  • Zur Realisierung der Batchlogik wird eine Batch-Ausführungs-Bean implementiert.

  • Falls für die Verarbeitung im Batch eigene Fachlogik benötigt wird, ist diese trotzdem den entsprechenden Anwendungskomponenten der zugehörigen Geschäftsanwendung hinzuzufügen.

  • Im Rahmen der Initialisierung hat die Ausführungs-Bean unter anderem die Aufgabe, die Konsistenz und Korrektheit der Eingabedaten zu prüfen.

  • Falls die zu verarbeitenden Sätze eines Batches das Ergebnis einer Datenbank-Query sind, ist in der Initialisierung die Query über eine Anwendungskomponente der zugehörigen Geschäftsanwendung abzusetzen. Diese Query soll die (fachlichen) Schlüssel von Entitäten, nicht Entitäten selbst auslesen.

  • Die Batches sind möglichst robust zu konstruieren: Falls auf ein fachliches Problem in der Ausführungs-Bean reagiert werden kann, sollte dies getan werden.

  • Batches erzeugen ein Ausführungsprotokoll. Der Batchrahmen, die Steuerungsimplementierung, die jeden Batch und dessen Arbeitsschritte steuert, stellt die notwendige Implementierung bereit. Die Ausführungs-Bean übermittelt dem Batchrahmen Status-Informationen für das Protokoll.

  • Batches verwenden einen (konfigurierten) technischen Benutzer, um sich vor Start der fachlichen Verarbeitung am IAM-Service des Anwendungssystems oder der Anwendungslandschaft zu authentifizieren.

  • Alle Batches zu einer Anwendung werden als eigenständige Deployment-Einheit ausgeliefert.

5.3.2. Klassendesign

KDBatch
Abbildung 6. Klassendesign eines Batches

Abbildung 6 zeigt eine beispielhafte Implementierung eines Batches, der die Komponenten Auskunft und Basisdaten verwendet.

Im Normalfall erhält die Batch-Bean (AuskunftBatch) eine Referenz auf die Komponenten des Anwendungskerns per Spring-Dependency. Für die Komponente Basisdaten erfolgt der Zugriff wie immer mittels statischer Aufrufe der DAOs.

Der Batchrahmen definiert das Interface BatchAusfuehrungsBean. Dieses dient der Steuerung des Batches durch den Batchrahmen. Es muss von der Batch-Ausführungs-Bean implementiert werden. Der Batchrahmen sorgt auch für die Initialisierung und Ausführung des Batches.

Der Batchrahmen übernimmt die Transaktionssteuerung. Die Transaktionssteuerung im Batch sieht vor, mehrere Arbeitsschritte in einer Transaktion abzuwickeln. Die Größe der Transaktion (Commit-Rate) wird über den Batchrahmen konfiguriert.

5.3.3. Realisierung

5.3.3.1. Einbinden der Bibliothek

Zur Realisierung von Batches muss die in Listing 11 aufgelistete Bibliothek eingebunden werden.

Listing 11. Einbindung der Bibliotheken zur Realisierung von Batches
<dependencies>
    ...
    <dependency>
        <groupId>de.bund.bva.isyfact</groupId>
        <artifactId>isy-batchrahmen</artifactId>
    </dependency>
    ...
</dependencies>
5.3.3.2. Implementierung der Batch-Logik

Die Batch-Logik wird implementiert, in dem eine Batch-Bean im Package <organisation>.<domäne>.<anwendung>.batch implementiert wird. Für die Realisierung ist es notwendig, dass die Batch-Bean das Interface BatchAusfuehrungsBean aus der Bibliothek isy-batchrahmen implementiert.

Der Batchrahmen ruft als Erstes die Methode initialisieren auf. Dabei werden alle zur Initialisierung benötigten Informationen übergeben. Details dazu werden im JavaDoc der Methode beschrieben.

Der Parameter BatchErgebnisProtokoll enthält eine Referenz auf ein Protokollobjekt, welches der Batch verwendet, um Protokoll-Meldungen und Statistiken an den Batchrahmen zu übergeben.

5.3.3.3. Konfiguration des Batches und Batchrahmens

Für jeden Batch muss eine Property-Datei in /src/main/resources/resources/batch angelegt werden. In dieser statischen Konfiguration werden unter anderem die Batch-ID und die Transaktionssteuerung konfiguriert. Eine Beschreibung der Parameter ist in Detailkonzept Komponente Batch enthalten.

Die betriebliche Konfiguration des Batches ist identisch zu derjenigen der zugehörigen Anwendung. Auch Parameter, die nur für den Batch benötigt werden, werden in die betriebliche Konfiguration der Geschäftsanwendung aufgenommen.

5.3.3.4. Spring-Konfiguration anlegen

Für den Batchrahmen werden in der Konfigurationsklasse der Batch-Schicht die Spring-Beans des Batchrahmens und für jeden existierenden Batch die Ausführungs-Bean als Spring-Bean definiert.

Zusätzlich müssen folgende Beans erstellt werden:

  • Eine Bean vom Typ BatchRahmenMBean zur Überwachung des Batchrahmens. Diese muss über den Spring MBeanExporter exportiert werden.

  • Eine Bean für den AufrufKontextVerwalter, die nicht den Scope thread hat. Ist in der Anwendungskonfiguration bereits eine Bean dieses Typs definiert, kann sie mit der Annotation @ExcludeFromBatchContext ausschließen.

  • Eine Bean für einen JpaTransactionManager.

  • Die Konfigurationsklasse der Batch-Schicht muss mit der Annotation

    @EntityScan("de.bund.bva.isyfact.batchrahmen.persistence.rahmen")

    versehen werden, damit die Entitäten des Batchrahmens gefunden werden.

Die Spring-Konfiguration der Anwendung kann auch für den Batches verwendet werden. Dazu müssen Beans, die nicht für Ausführung eines Batches instanziiert werden sollen, mit @ExcludeFromBatchContext annotiert werden.

5.3.3.5. Konfiguration des Batch-Deployments

Für das Deployment des Batches wird ein neues Maven-Projekt <system>-batch angelegt. Dieses hat die Aufgabe das Deployment-Paket für den Batch zusammenzustellen.

Dazu wird eine neue pom.xml angelegt, die als Ziel-Typ ein Jar mit allen Dateien des Batches erzeugt. Zusätzlich können in diesem Projekt Shell-Skripte und ähnliches für den Batch abgelegt werden.

Das Batch-Projekt enthält keinen Java-Code. Die Batch-Beans liegen im normalen Anwendungsprojekt.

6. Querschnitt

In diesem Kapitel wird die Umsetzung querschnittlicher Aspekte beschrieben.

6.1. Logging

In diesem Abschnitt wird beschrieben, wie das Logging umzusetzen und zu konfigurieren ist.

6.1.1. Designvorgaben

  • Für Logging wird die Bibliothek isy-logging verwendet.

  • Es wird ein Debug-, Info- und ein Error-Log geführt. Die Zuordnung der Log-Levels auf diese Log-Arten wird im Dokument Konzept Logging definiert. Ebenso welche Informationen mit welchem Log-Level ausgeben werden sollen.

  • Für das Logging wird die im Rahmen der IsyFact erstellten Layouts für Entwicklung und Produktion verwendet.

  • In jeder Log-Meldung ist eine Correlation-ID mitzuloggen. Diese identifiziert den Aufruf über die Anwendungslandschaft hinweg.

6.1.2. Realisierung

6.1.2.1. Implementierung von Log-Ausgaben

Log-Ausgaben können an beliebigen Stellen im Code erzeugt werden. Dazu wird in jeder Klasse ein eigener Logger erzeugt (Listing 12).

Listing 12. Erzeugen eines Loggers
public class MyClass {
...
   private static final IsyLoggerStandard LOG = IsyLoggerFactory.getLogger(MyClass.class);
...

Der IsyLoggerStandard ist dabei für technisches Logging gedacht. Je nach Anwendungsszenario sind andere spezifische Logger (IsyLoggerFachdaten, IsyLoggerTypisiert) zu verwenden.

Wichtig ist, in der Exception-Fassade an der Service-Schnittstelle (siehe Kapitel Klassendesign) die Correlation-ID zu setzen:

public class ServiceSchnittstelleExceptionFassade {

    @StelltLoggingKontextBereit
    public Object serviceMethode(AufrufKontext kontext, Parameter serviceParameter) {
        // ...
    }
}
6.1.2.2. Einbinden der Bibliotheken

Um die Logging Funktionen in der eigenen Anwendung nutzen zu können müssen die in Listing 13 aufgelisteten Bibliotheken eingebunden werden.

Listing 13. Einbindung der Bibliotheken zur Nutzung des Logging
<dependencies>
    ...
    <dependency>
        <groupId>de.bund.bva.isyfact</groupId>
        <artifactId>isy-logging</artifactId>
    </dependency>
    ...
</dependencies>

Dadurch wird die Bibliothek isy-logging sowie Logback als verwendetes Produkt automatisch in die Anwendung integriert.

6.1.2.3. Anlegen der Konfiguration

In /src/main/resources/ muss die Datei logback-spring.xml angelegt werden. Diese definiert, wohin Log-Ausgaben geschrieben werden und wie das Layout dafür ist. Die Bibliothek isy-logging bringt fertig konfigurierte Layouts mit, die dort eingebunden werden.

6.2. Konfiguration

Deprecation

Dieser Teil der Dokumentation ist veraltet und wird in einem zukünftigen Release entfernt. Die Inhalte sollten zur Entwicklung neuer Anwendungen nicht mehr berücksichtigt werden.

In diesem Kapitel wird die Verarbeitung von Konfigurationen in Anwendungen beschrieben.

6.2.1. Designvorgaben

  • Für die Konfiguration werden betriebliche, statische und Benutzerkonfigurationen unterschieden. Eine Definition und Kriterien zur Typisierung können in Konzept Konfiguration nachgelesen werden.

  • Die betriebliche Konfiguration wird in /src/main/resources/config/application.properties abgelegt.

  • Statische Konfigurationen werden als Datei in /src/main/resources/resources abgelegt.

  • Benutzerkonfigurationen werden in der Datenbank abgelegt.

  • Betriebliche Konfigurationen können in Ausnahmefällen zur Laufzeit aktualisiert werden.

  • Für das Laden von betrieblichen Konfigurationen werden @ConfigurationProperties-Klassen verwendet.

6.2.2. Realisierung

6.2.2.1. Auslesen von Konfigurationsparametern in der Anwendung

Für den Zugriff auf Konfigurationsparameter in application.properties werden Klassen erstellt, die beim Start der Anwendung mit den Werten aus application.properties befüllt werden. Der Zugriff auf diese Klassen ist typsicher und die Werte können zusätzlich mit Bean Validierung überprüft werden. Zur Verwendung in den Komponenten der Anwendung oder zur Konfiguration von Spring Beans werden diese Klassen per Dependency Injection verfügbar gemacht. Details zur Implementierung siehe Konzept Konfiguration.

6.3. Fehlerbehandlung

In diesem Kapitel wird beschrieben, wie die Fehlerbehandlung durchzuführen ist.

6.3.1. Designvorgaben

  • In jeder Anwendung bzw. Bibliothek wird eine eigene Exception-Hierarchie angelegt.

  • Für Anwendungs-Exceptions wird die oberste Exception dieser Hierarchie von den in der Bibliothek isy-exception-core enthaltenen Exception-Klassen abgeleitet. Diese Ober-Exceptions sind als abstrakt zu kennzeichnen.

  • Für Exceptions in selbst entwickelten Bibliotheken werden nicht die Exception-Klassen aus isy-exception-core verwendet. Die zugrundeliegenden Designprinzipien sind jedoch identisch umzusetzen. So wird für jede Bibliothek eine abstrakte Ober-Exception angelegt. Diese sorgt für das Laden der Nachrichten, erbt aber direkt von einer der java.lang.Exception bzw. java.lang.RuntimeException.

  • Fehlertexte werden in Resource-Bundles ausgelagert und über eine Fehler-ID identifiziert. Die Schlüssel der Fehler-IDs werden in einer Konstantenklasse zusammengefasst.

  • Exceptions werden grundsätzlich nur zur Signalisierung abnormer Ergebnisse bzw. Situationen eingesetzt.

  • Exceptions sind in der Regel zu behandeln und zu loggen. Ist es nicht möglich die Exception zu behandeln, muss sie an den Aufrufer weitergegeben werden. Die Exception wird im Fall eines Weiterwerfens nicht geloggt.

  • Nur Exceptions in Methodensignaturen verwenden, die auch vorkommen können.

  • Bei der Behandlung von Fehlern ist ein geordneter Systemzustand herzustellen, z. B. das Schließen der Datenbankverbindung über einen finally-Block.

  • Fehler sollten möglichst früh erkannt werden und zu entsprechenden Ausnahmen führen.

  • Interne Exceptions dürfen in der Service-Schnittstelle nicht vorkommen.

  • Catch-Blöcke dienen der Fehlerbehandlung und dürfen nicht als else-Zweige genutzt werden.

  • Keine leeren Catch-Blöcke.

  • Das destruktive Wrappen einer Exception zerstört den StackTrace und ist nur für Exceptions an den Außen-Schnittstellen sinnvoll. Destruktiv gewrappte Exceptions sind in jedem Fall vor dem Wrappen zu loggen.

Weitere Hinweise für die richtige Behandlung von Fehlern sind in Konzept Fehlerbehandlung enthalten.

6.3.2. Paketstruktur

Exceptions die querschnittlich, also von mehreren Komponenten genutzt werden, werden im Paket:

<organisation>.<domäne>.<anwendung>.common.exception

<organisation> z.B. bva.bund.de

implementiert. Komponentenspezifische Exceptions, also solche die nur von einer einzigen Komponente genutzt werden, gehören in das Paket:

<organisation>.<domäne>.<anwendung>.core.<komponente>

6.3.3. Realisierung

Die Bibliothek ist in zwei Teile aufgeteilt: isy-exception-core und isy-exception-sst. Das Core-Paket enthält anwendungsinterne Exception-Klassen und Hilfsklassen für das Exception-Mapping. Im Schnittstellen-Projekt sind die Klassen für die Transport-Exceptions enthalten. Wenn das Core-Paket eingebunden wird, wird über Maven automatisch das Schnittstellen-Projekt mit eingebunden. Die explizite Einbindung von isy-exception-sst sollte dann entfernt werden.

Die Core-Bibliothek wird im Wesentlichen im Anwendungskern bzw. der Service-Schnittstellen-Implementierung benötigt (siehe Bibliotheken für die Implementierung der Service-Schnittstelle). Für Service-Schnittstellen werden lediglich die Transport-Exceptions aus isy-exception-sst benötigt (siehe Kapitel Bibliotheken für das Service-Schnittstellen-Projekt).

6.3.3.1. Einbinden der Bibliothek

Zur Realisierung der Fehlerbehandlung und Implementierung von Exceptions müssen die in Listing 14 aufgelisteten Bibliotheken eingebunden werden.

Listing 14. Einbindung der Bibliotheken für die Fehlerbehandlung
<dependencies>
    ...
    <dependency>
        <groupId>de.bund.bva.isyfact</groupId>
        <artifactId>isy-exception-core</artifactId>
    </dependency>
    <dependency>
        <groupId>de.bund.bva.isyfact</groupId>
        <artifactId>isy-util</artifactId>
    </dependency>
    ...
</dependencies>

isy-exception-core enthält abstrakte Exception-Klassen die in Anwendungen zu verwenden sind. isy-util enthält Hilfsklassen zum Laden von Fehlertexten.

6.3.3.2. Anlegen der Exception-Klassen

In jeder Anwendung wird für jede Exception-Art (technisch, fachlich) eine eigene Oberklasse angelegt. Diese erbt von der entsprechenden Klasse aus isy-exception-core. Zum Laden der Fehlertexte wird das Interface FehlertextProvider aus derselben Bibliothek verwendet. In isy-util ist die Implementierung MessageSourceFehlertextProvider enthalten. Diese unterstützt das Laden von Fehlertexten aus einer Spring-Message-Source.

6.3.3.3. Fehlerbehandlung an der Anwendungsschnittstelle

Fehler sind entweder zu behandeln und zu loggen oder weiterzuwerfen. Es muss jedoch sichergestellt werden, dass interne Fehler der Anwendung nicht über die System-Schnittstelle (siehe Anbieten von Service-Schnittstellen) geworfen werden. Dazu wird in der Exception-Fassade eine explizite Fehlerbehandlung mit einem Catch-Throwable-Block durchgeführt.

Alle Exceptions der Anwendungen werden hier in Transport-Exceptions umgewandelt. Dazu wird das im Folgenden beschrieben Muster verwendet.

Es wird ein Catch-Block für alle auftretenden eigenen Exceptions angelegt. In jedem Catch-Block wird die Exception geloggt und über ExceptionMapper.mapException() in eine passende Transport-Exception umgewandelt. Als Letztes wird ein Catch-Throwable-Block eingefügt.

Hier wird für die aufgetretene Exception über ExceptionMapper.createToException() eine neue Transport-Exception erzeugt. Zur Ermittlung der Fehler-ID wird eine Klasse AusnahmeIdUtil angelegt. Diese implementiert eine statische Methode getAusnahmeId, die zu einer übergebenen Exception eine passende Fehler-ID ermittelt. Vor dem Werfen der so erzeugten Exception über die Schnittstelle wird ein Log-Eintrag erzeugt.

Beim Umwandeln der internen Exceptions in Transport-Exceptions wird der Stack-Trace der internen Exceptions verworfen.

6.4. Aufrufkontextverwaltung

Deprecation

Dieser Teil der Dokumentation ist veraltet und wird in einem zukünftigen Release entfernt. Die Inhalte sollten zur Entwicklung neuer Anwendungen nicht mehr berücksichtigt werden. Stattdessen wird empfohlen, Konzept Security zu verwenden.

Anmerkung zur Deprecation

Ab der IF 3.0 wird der Spring SecurityContext anstatt des AufrufKontext verwendet. Der AufrufKontextVerwalter kann somit auch nicht mehr verwendet werden. Die Verwendung des SecurityContext anstelle des AufrufKontext-Objekts wird im Baustein isy-security beschrieben.

Einige Komponenten der Anwendung, z.B. die Protokollierung oder die Autorisierung benötigen Kontextinformationen über den Aufrufer. Damit diese nicht durch die gesamte Anwendung gereicht werden müssen, kann in der Anwendung ein AufrufKontextVerwalter verwendet werden.

6.4.1. Designvorgaben

  • Die Komponente wird so implementiert, dass sie spezifische Informationen über den Aufrufkontext speichern kann (z.B. Name des aufrufenden Benutzers).

  • Die Komponente kann in einer Anwendung so erweitert werden, dass sie beliebige weitere Kontext-Informationen aufnehmen kann.

6.4.2. Realisierung

6.4.2.1. Einbinden der Bibliothek

Zur Realisierung des Aufrufkontextes müssen die in Listing 15 aufgelisteten Bibliotheken eingebunden werden.

Einbindung der Bibliotheken zur Nutzung des Aufrufkontextes

<dependencies>
    ...
    <dependency>
        <groupId>de.bund.bva.isyfact</groupId>
        <artifactId>isy-aufrufkontext</artifactId>
    </dependency>
    ...
</dependencies>

Die Bibliothek isy-aufrufkontext enthält die Komponente AufrufKontextVerwalter, welcher den benutzerspezifischen Aufrufkontext im Thread-Scope (alternativ Request-Scope) hält.

6.4.2.2. Konfiguration der Bibliothek

Die Komponente AufrufKontextVerwalter wird als Spring-Bean konfiguriert. Dabei wird festgelegt, dass Spring eine neue Instanz für jeden Thread (alternativ Request) anlegen soll:

Listing 15. Spring-Konfiguration der Bean AufrufKontextVerwalter
@Bean
@Scope(value="request", proxyMode = ScopedProxyMode.TARGET_CLASS)
public AufrufKontextVerwalter aufrufKontextVerwalter(){
    return new AufrufKontextVerwalterImpl();
}
Die Scopes thread und request werden mit dem Einbinden der Bibliothek isy-sicherheit registriert.

Der vom AufrufKontextVerwalter verwaltete AufrufKontext wird beim Aufruf der Anwendung in der Service-Schnittstelle oder im Controller der GUI gesetzt und steht fortan, während der Verarbeitung des Requests, in der gesamten Anwendung zur Verfügung.

Komponenten, die diese Informationen benötigen, erhalten dazu einfach eine Referenz auf den AufrufKontextVerwalter per Dependency Injection.

Zur Entgegennahme des Aufrufkontextes an der Service-Schnittstelle wird die Annotation @StelltAufrufKontextBereit verwendet. Die Konfiguration ist im Dokument Nutzungsvorgaben Sicherheit beschrieben.

6.5. Authentifizierung und Autorisierung

Deprecation

Dieser Teil der Dokumentation ist veraltet und wird in einem zukünftigen Release entfernt. Die Inhalte sollten zur Entwicklung neuer Anwendungen nicht mehr berücksichtigt werden. Stattdessen wird empfohlen, OAuth 2.0 zur Autorisierung zu verwenden.

Anmerkung zur Deprecation

Ab der IF 3.0 wird der AufrufKontext nicht mehr verwendet und als Autorisierungsprotokoll wird OAuth 2.0 eingesetzt. Die Autorisierung nach OAuth 2.0 wird im Baustein isy-security beschrieben.

Dieses Kapitel beschreibt die Realisierung der Authentifizierung und Autorisierung von Anfragen.

6.5.1. Designvorgaben

  • Die Authentifizierung von Anfragen wird im Servicegateway und im Portal mithilfe des IAM-Services durchgeführt.

  • Prozesse, die innerhalb des Anwendungssystems oder der Anwendungslandschaft starten (z.B. Timertasks, Batches) verwenden einen technischen Benutzer und authentifizieren diesen selbständig gegen den IAM-Service.

  • Die Berechtigungsprüfung ist in der Anwendung deklarativ zu definieren bzw. zu programmieren.

  • Eine erste Berechtigungsprüfung erfolgt in der Service-Schnittstelle oder im Web-GUI-Dialogcontroller jeder Anwendung. Es wird geprüft, ob der Aufrufer den Service oder den Dialog überhaupt verwenden darf.

  • In jeder Service-Methode wird ein Parameter AufrufKontext mit den Daten des aufrufenden Benutzers übermittelt. Dieser Parameter wird im AufrufKontextVerwalter hinterlegt und beim Aufruf weiterer Nachbarsysteme durchgereicht.

  • In der Web-GUI wird ein vom IAM-Service bereitgestellter HTTP-Header mit den Daten des aufrufenden Benutzers entgegengenommen und in einen AufrufKontext gewandelt. Dieser Parameter wird im AufrufKontextVerwalter hinterlegt und beim Aufruf weiterer Nachbarsysteme durchgereicht.

6.5.2. Realisierung

6.5.2.1. Einbinden der Bibliothek

Zur Realisierung der Autorisierung müssen die in Listing 17 aufgelisteten Bibliotheken eingebunden werden.

Listing 16. Einbindung der Bibliotheken zur Authentifizierung und Autorisierung
<dependencies>
    ...
    <dependency>
        <groupId>de.bund.bva.isyfact</groupId>
        <artifactId>isy-sicherheit</artifactId>
    </dependency>
    <dependency>
        <groupId>de.bund.bva.isyfact</groupId>
        <artifactId>isy-serviceapi-sst</artifactId>
    </dependency>
    ...
</dependencies>

Die Bibliothek isy-sicherheit enthält die Komponenten Sicherheit und BerechtigungsManager.

Die Bibliothek isy-serviceapi-sst enthält das Transportobjekt AufrufKontextTo, das zur Übermittlung der Authentifizierungsdaten über Schnittstellenaufrufe benutzt wird.

Zusätzlich wird als Abhängigkeit der AufrufKontextVerwalter (siehe Aufrufkontextverwaltung) benötigt, der die Informationen zum Aufrufer kennt.

6.5.2.2. Konfiguration der Sicherheitskomponente

Die Komponente Sicherheit wird als Spring-Bean in einer Konfigurationsklasse konfiguriert.

Die einer Rolle zugeordneten Rechte werden in der Datei /src/main/resources/resources/rollenrechte.xml konfiguriert.

6.5.2.3. Prüfen der Berechtigung

Die Berechtigungsprüfung erfolgt in der Regel vor der fachlichen Verarbeitung in der Service-Schnittstelle oder im Dialog-Controller einer Anwendung. Dies erfolgt über Annotationen oder im Webflow (siehe Nutzungsvorgaben Sicherheit). Es kann auch jederzeit auf das Bean Sicherheit zugegriffen werden, um einen Berechtigungsmanager zu verwenden.

Berechtigungsmanager manager = sicherheit.getBerechtigungsManager();
manager.pruefeRecht(RechteSchluessel.RECHT_MELDEN);

Über die Methoden des Berechtigungsmanagers (z.B. hatRecht, pruefeRecht) kann die Anwendung die Autorisierung durchführen.

6.6. Überwachung

In diesem Abschnitt wird beschrieben, wie die Überwachung einer Anwendung realisiert wird.

Detaillierte Informationen zur Überwachung sind im Dokument Konzept Überwachung und in Nutzungsvorgaben Überwachung enthalten.

6.6.1. Designvorgaben

  • Die Erreichbarkeit des Systems wird über einen HealthCheck von Spring Boot Actuator realisiert.

  • Server-Metriken werden anbieterneutral mit Micrometer angeboten.

  • Einzelne Services können detailliert überwacht werden. Dazu stellen die Services Statistiken über ihre Nutzung als Metriken bereit.

  • Zur Steuerung des Loadbalancing ist ein Servlet enthalten, um die Anwendung innerhalb eines Clusters deaktivierbar zu machen.

6.6.2. Realisierung

6.6.2.1. Einbinden der Bibliothek

Zur Realisierung der Überwachung muss die in Listing 18 aufgelistete Bibliothek eingebunden werden.

Listing 17. Einbindung der Bibliothek zur Überwachung von Anwendungen
<dependencies>
    ...
    <dependency>
        <groupId>de.bund.bva.isyfact</groupId>
        <artifactId>isy-ueberwachung</artifactId>
    </dependency>
    ...
</dependencies>
6.6.2.2. Konfiguration der Überwachungsschnittstelle

Der HealthCheck, die Server-Metriken und das Loadbalancing Servlet werden automatisch durch die Verwendung der Bibliothek in die Anwendung eingebunden und aktiviert. Für den HealthCheck muss explizit eine Konfiguration in den Application Properties erfolgen, damit der Health-Status automatisch aktualisiert wird.

Die im Detail zu überwachenden Services müssen explizit konfiguriert werden. Dazu werden die Service-Beans in Service-Statistik-Beans gekapselt, und jeder Service-Aufruf wird durch die Service-Statistik-Beans delegiert. Die Konfiguration besteht aus zwei Teilen:

  • Konfigurieren der Service-Statistik-Beans als Spring Beans.

  • Anbinden der Service-Statistik-Beans an die Service-Beans durch einen AOP-Advice. Dieser Advice wird so konfiguriert, dass bei jedem Aufruf einer Methode der Service-Bean die Statistik-Bean aufgerufen wird.