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 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 geraten wird, ignorieren wir in dem Tutorial. Im unteren Teil des Dialogs gibt es einen Link, mit dem Sie die benötigte JUnit Library zum Java Build Path des Projektes hinzufügen können. Der nächste Kasten enthält den Sourcecode der Testfallklasse.

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

public class TutorialTest extends TestCase {

	private IRuntimeRepository repository;
	private HausratProdukt kompaktProdukt;
	private HausratProduktAnpStufe kompaktAnpStufe;

	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 2015-09");

		// Juengste ProductAnpassungsstufe holen (wir wissen es gibt nur eine).
		IProductComponentGeneration pcGen = pc.getLatestProductComponentGeneration();

		kompaktAnpStufe = (HausratProduktAnpStufe) pcGen;

		// Auf die eigenen Modellklassen casten
		kompaktProdukt = (HausratProdukt) pc; // wird im weiteren Verlaufbenoetigt.
	}

	@Test
	public void testProduktdatenLesen() {
		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.