Modellierung und Produktkonfigurierung

Zugriff auf Produktinformationen zur Laufzeit

Nachdem wir die Produktdaten erfasst haben, beschäftigen wir uns nun damit, wie man zur Laufzeit (in einer Anwendung/einem Testfall) auf diese zugreift. Hierzu werden wir einen JUnit-Test schreiben, den wir im Laufe des Tutorials weiter ausbauen.

Zum Zugriff auf Produktdaten stellt Faktor-IPS das Interface „IRuntimeRepository“ bereit. Die Implementierung ClassloaderRuntimeRepository erlaubt den Zugriff auf die mit Faktor-IPS erfassten Produktdaten und lädt die Daten über einen Classloader. Damit dies möglich ist, macht Faktor-IPS zwei Dinge:

  1. Die Dateien, die die Produktinformationen enthalten, werden in den Java Sourcefolder mit dem Namen „derived“ kopiert. Damit sind diese Dateien im Build Path des Projektes enthalten und können über den Classloader geladen werden.

  2. Welche Daten sich im ClassloaderRuntimeRepository befinden, ist in einem Inhaltsverzeichnis vermerkt. Dieses Inhaltsverzeichnis (Englisch: table of contents, toc) wird von Faktor-IPS ebenfalls in eine Datei generiert, die als Toc-File bezeichnet wird. Die Datei heißt standardmäßig „faktorips-repository-toc.xml“ [13].

[13] Die Namen lassen sich in der „.ipsproject“ Datei im Abschnitt IpsObjectPath konfigurieren.

Ein ClassloaderRuntimeRepository wird über die statische create(…​)-Methode der Klasse erzeugt. Als Parameter wird der Pfad zum Toc-File übergeben. Das Toc-File wird direkt beim Erzeugen des Repositorys über Classloader.getResourceAsStream() gelesen. Alle weiteren Daten werden erst (wiederum über den Classloader) geladen, wenn auf sie zugegriffen wird.

Das Laden der Daten über den Classloader hat im Gegensatz zum Laden aus dem Filesystem den großen Vorteil, dass es völlig plattformunabhängig ist. So kann der Programmcode z.B. ohne Änderungen auf z/OS laufen.

Einen Produktbaustein kann man über die Methode getProductComponent(…​) erhalten. Als Parameter übergibt man die RuntimeId des Bausteins. Da das Interface „IRuntimeRepository“ unabhängig vom konkreten Modell (in unserem Fall also dem Hausratmodell) ist, muss man das Ergebnis noch auf die konkrete Produktklasse casten.

Probieren wir dies doch einmal in einem JUnit Testfall aus. Legen Sie hierzu zunächst im Projekt Hausratprodukte einen neuen Java Sourcefolder „test“ an. Am einfachsten geht dies, indem Sie im Package-Explorer das Projekt markieren und im Kontextmenü Build PathNew Source Folder…​aufrufen.

Danach markieren Sie den neuen Sourcefolder und legen einen JUnit Testfall an, indem Sie in der Toolbar auf den Pfeil neben dem Icon

testcase

klicken und dann JUnit Test Case auswählen. In dem Dialog geben Sie als Namen für die Testfallklasse „TutorialTest“ ein und haken an, dass auch die setUp() Methode generiert werden soll. Die Warnung, dass die Verwendung des Defaultpackages nicht empfohlen wird, ignorieren wir in dem Tutorial. Für unseren Test verwenden wir die JUnit 5 JUnit Jupiter. Beim Beenden des Wizards werden wir gefragt, ob wir die JUnit Library zum Build Path des Projektes hinzufügen wollen. Klicken Sie in diesem Dialog auf OK. Der nächste Kasten enthält den Sourcecode der Testfallklasse.

junit wizard
Figure 1. Wizard zur Erstellung eines JUnit Tests

Anstatt die Korrektheit der Produktdaten mit assert*-Statements zu testen, geben wir sie hier mit println auf der Konsole aus.

public class TutorialTest {

    private IRuntimeRepository repository;
    private HausratProdukt kompaktProdukt;

    @BeforeEach
    public void setUp() throws Exception {
        // Repository erzeugen
        repository = ClassloaderRuntimeRepository.create(
                "org/faktorips/tutorial/produktdaten/internal/faktorips-repository-toc.xml");

        // Referenz auf das Kompaktprodukt aus dem Repository holen
        IProductComponent pc = repository
                .getProductComponent("hausrat.HR-Kompakt 2019-07");

        // Auf die eigenen Modellklassen casten
        kompaktProdukt = (HausratProdukt) pc;
    }

    @Test
    public void test() {
        System.out.println("Produktname: " + kompaktProdukt.getProduktname());
        System.out.println("Vorschlag Vs pro 1qm: "
                + kompaktProdukt.getVorschlagVersSummeProQm());
        System.out.println("Default Zahlweise: "
                + kompaktProdukt.getDefaultValueZahlweise());
        System.out.println("Erlaubte Zahlweisen: "
                + kompaktProdukt.getAllowedValuesForZahlweise(null));
        System.out.println(
                "Default Vs: " + kompaktProdukt.getDefaultValueVersSumme());
        System.out.println(
                "Bereich Vs: " + kompaktProdukt.getRangeForVersSumme(null));
        System.out.println("Default Wohnflaeche: "
                + kompaktProdukt.getDefaultValueWohnflaeche());
        System.out.println("Bereich Wohnflaeche: "
                + kompaktProdukt.getRangeForWohnflaeche(null));
    }
}

Wenn Sie den Test nun ausführen, sollte er folgendes ausgeben:

Produktname: Hausrat Kompakt
Vorschlag Vs pro 1qm: 600.00 EUR
Default Zahlweise: 1
Erlaubte Zahlweisen: [1, 2]
Default Vs: MoneyNull
Bereich Vs: 10000.00 EUR-2000000.00 EUR
Default Wohnflaeche: null
Bereich Wohnflaeche: 0-1000

Damit haben wir einen Einblick in die Modellierung mit Faktor -IPS bekommen, haben erste, einfache Produkte angelegt und zur Laufzeit auf Produktdaten zugegriffen.

In Teil 2 werden wir in die Verwendung von Tabellen & Formeln einführen. Diese werden wir nutzen, um das Hausratmodell so zu erweitern, dass den Produkten flexibel Zusatzdeckungen durch Anwender aus der Fachabteilung hinzu konfiguriert werden können, ohne dass das Modell erweitert werden muss.