Vom Domänenmodell zur ausführbaren Anwendung

Agile Entwicklung mit jMatter

Markus Demolsky

Jede Applikation ist in sich einzigartig und deckt eine definierte Domäne ab. Bevor jedoch mit der Lösung von immer wieder neu entstehenden Problemen begonnen werden kann, muss eine grundlegende Infrastruktur gebildet werden. Dazu zählen etwa Domänenmodell, Datenzugriffsschicht, GUI und Logging. Dabei werden immer wieder die gleichen Tätigkeiten durchgeführt, wie etwa die Anpassung der einzelnen DAOs oder das Logging an das entsprechende Domänenmodell. In diesem Artikel soll ein Weg gezeigt werden, die Infrastruktur für beliebige Domänenmodelle generisch zu erzeugen.

jMatter verfolgt den Domain-Driven-Design-Ansatz, d.h. im Zentrum steht das Domänenmodell. Es handelt sich um ein Framework, welches das Naked-Objects-Architektur-Pattern implementiert. Bei Naked Objects steht das Domänenobjekt (Kunde, Artikel etc.) im Mittelpunkt (Abb. 1), welches mit Aspekten (GUI, Validierung, Logging etc.) umhüllt wird. Diese Aspekte haben zum Großteil nicht direkt etwas mit der Problemdomäne zu tun, sondern sollten von jeder Anwendung (jeglicher Domäne) zur Verfügung gestellt werden und nehmen auch in der Entwicklung sehr viel Zeit in Anspruch. Mithilfe von jMatter können solche Aspekte generisch erzeugt und (sofern es das Framework zulässt) an die eigenen Bedürfnisse angepasst werden. Mit diesem Ansatz kann sich der Entwickler nur noch auf die Problemdomäne konzentrieren und erste Prototypen des neuen Systems können in rascher Zeit umgesetzt werden. So ist es auch möglich, während Workshops Anpassungen gemeinsam mit dem Kunden in Echtzeit umzusetzen. Hier kann man durchaus schon von agiler Entwicklung reden.
Mit jMatter lassen sich folgende Aspekte für ein Domänenmodell erstellen:

  • GUI mit Swing und Unterstützung für CRUD-Operationen
  • Persistierung mit O/R-Mapper Hibernate
  • Authentifizierung
  • Built-in Support für Abfragenkonstruktionen
  • Support für Wizards, Kalender-Ansichten

Die Architektur von jMatter ist auf Workgroup Business Anwendungen ausgelegt, welche in einem lokalen Netz von mehreren Usern gleichzeitig betrieben werden können.

Abb. 1: Domänenmodell
jMatter einrichten

jMatter ist nicht einfach eine Bibliothek, die in das eigene Projekt eingebunden wird, sondern stellt eine Art Toolbox zur Verfügung. Voraussetzungen für jMatter sind Java 5, Ant 1.6.5 und eine relationale Datenbank, die von Hibernate unterstützt wird. Nachdem die ZIP-Datei entpackt ist, können wir schon starten. In den folgenden Abschnitten werde ich ein einfaches Beispiel mit Autoren erstellen.

Projekt erstellen

Um ein neues Projekt zu erstellen muss folgender Befehl im Root-Verzeichnis von jMatter eingegeben werden:

ant new-project -Dnew.project.name=JavaMagazin

Basierend auf dem Projekt-Template wird nun das JavaMagazin-Projekt erstellt. Dazu greift jMatter auf den Ordner project-template im Root-Verzeichnis zurück. Dieser stellt eine vorgefertigte Ordnerstruktur und eine Menge an Konfigurationsdateien (Hibernate, Deployment etc.) zur Verfügung, welche nur noch an die eigenen Bedürfnisse angepasst werden müssen. Des Weiteren besitzt jedes Projekt eine build.xml mit vordefinierten Goals, welche für das Erstellen der Anwendung benötigt werden. Nachdem die Grundstruktur unseres Projekts erfolgreich erstellt wurde, erzeugen wir über Eclipse ein neues Java Projekt, das auf diesen Ordner verweist. Benötigte Bibliotheken wurden bereits von jMatter in den Unterordner lib kopiert und sollten auch in Eclipse im Classpath aufgenommen worden sein.

Domänenmodell

Im DDD beginnen wir immer mit dem Domänenmodell. Für unser Beispiel-Projekt benötigen wir Autoren. Listing 1 zeigt das Domänenmodell Autor.

Listing 1: Autor Domänenmodell 
-----------------------------------------------------
public class Autor extends AbstractComplexEObject {
    private final StringEO name = new StringEO();
    private final StringEO job = new StringEO();
    private final StringEO street = new StringEO();
    private final StringEO city = new StringEO();
    private final StringEO zipCode = new StringEO();
    
    public static String[] fieldOrder = { "name", "job","street", "city", "zipCode" };
    public static Color colorCode = new Color(0x0dA858);

    public Autor() {
    }

    public StringEO getName() {
        return name;
    }

    public StringEO getStreet() {
        return street;
    }

    public StringEO getCity() {
        return city;
    }

    public Title title() {
        return name.title();
    }
}

Entwickler, die mit Hibernate arbeiten, sind gewohnt ihr Domänenobjekt als POJO zu implementieren. Bei jMatter erbt jedes Domänenobjekt von der Klasse AbstractComplexEObject  und die einzelnen Attribute werden mit nicht-primitiven Datentypen deklariert. Der Grund dafür ist das Naked Object Architektur Pattern. Des Weiteren muss jedes Domänenmodell einen Titel (getTitle) zurückliefern, um in der GUI die Objekt-Titel anzeigen zu können (z.B.: Übersichten). Zudem wird die Reihenfolge der Felder definiert (fieldOrder). In dieser Reihenfolge erscheinen die Eingabefelder in den Dialogen.

Persistierung

jMatter greift auf den O/R-Mapper Hibernate zurück. Aber keine Angst, man muss kein Hibernate Spezialist sein, um die Persistierung der Objekte zu konfigurieren. Nicht einmal ein Mapping File ist notwendig, denn dies wird von der Toolbox erzeugt. Es kann aber nicht schaden, die Grundkenntnisse der Mapping-Prinzipien von Hibernate zu verstehen, um bei Bedarf die generierten Mapping Files nachträglich zu optimieren. Im Unterordner resources befindet sich die Konfigurationsdatei hibernate.properties, welche entsprechend an die eigene Datenbank angepasst werden muss.

Damit jMatter weiß, welche Domänenobjekte persitiert werden sollen, muss die Konfigurationsdatei  src/com/u2d/app-config.xml angepasst werden (Listing 2).

In der jetzigen Version kann jMatter nur eine Swing-Oberfläche für das Domänenmodell erzeugen. Das nächste Release wird aber auch einen Webview-Mechanismus zur Verfügung stellen. Ich konzentriere mich jetzt auf die Swing-Oberfläche. Die Art des View-Mechanismus wird über <view-mechanism> festgelegt. Der Entwickler könnte auch seine eigene Oberfläche erstellen und müsste nur das entsprechende ViewMechanismus-Interface implementieren und hier konfigurieren.

Für die Persistierung ist der <persistence-mechanismus> und <persist-classes-> von Bedeutung. Standardmäßig ist der HBMSingleSession, welcher für die Hibernate-Persistierung zuständig ist, aktiviert. Bei den <perist-classes> werden alle Domänenobjekte aufgelistet, welche persistiert werden sollen. Hier finden wir auch wieder das Autor-Domänenobjekt. Neben dem Domänenobjekt sind noch weitere Objekte, wie Folder, Query, User etc. in dieser Liste aufgeführt. Dabei handelt es sich um jMatter interne Objekte, die ebenfalls persistiert werden können. Es können zudem Abfragen auf Daten definiert und anschließend gespeichert werden, um nicht immer die Abfrage neu zu definieren.

Listing 2: Auszug aus der app-config.xml 
-------------------------------------------------------
com.u2d.view.swing.SwingViewMechanismMetal15com.u2d.persist.HBMSingleSessionat.demolsky.jmatter.javamagazin.Autorcom.u2d.type.composite.ContactMethodcom.u2d.type.composite.Foldercom.u2d.find.CompositeQuerycom.u2d.type.composite.LoggedEventcom.u2d.app.Usercom.u2d.app.Rolecom.u2d.restrict.CommandRestrictioncom.u2d.restrict.FieldRestrictioncom.u2d.restrict.Restrictioncom.u2d.reporting.SimpleReport

jMatter besitzt nun alle notwendigen Informationen, um das Datenbankschema zu generieren. Für die Schema-Generierung bietet die build.xml im Projekt ein passendes Goal an: ant schema-export. Mit diesem Befehl werden zuerst die Hibernate Mapping Files der einzelnen Domänenobjekte im <persit-classes>-Abschnitt generiert. Anschließend wird das gesamte Datenbankschema in der definierten Datenbank (hibernate.properties) aktualisiert.

GUI-Konfiguration

Eine Anwendung gliedert sich üblicherweise in mehrere Aufgabenbereiche (Stammdaten, Auftrag, Administration etc.). Meistens stellen Applikationen dafür Menüs oder Toolbars zur Verfügung. jMatter bietet hier eine Toolbar an, die über die Konfigurationsdatei class-list.xml im Ordner src/com/u2d/class-list.xml konfiguriert wird (Listing 3). In den Abschnitten Model und Admin werden wieder jMatter vorgefertigte Typen definiert, welche aber nicht zwingend verwendet werden müssen.

Listing 3: Auszug aus der class-list.xml 
--------------------------------------------------------
Class ListStammdatenat.demolsky.jmatter.javamagazin.AutorModelcom.u2d.type.composite.Foldercom.u2d.find.CompositeQuerycom.u2d.reporting.SimpleReportAdmincom.u2d.app.Usercom.u2d.type.composite.LoggedEventcom.u2d.model.ComplexType

Bevor wir nun das Programm starten, möchten wir noch einen schönen Splash Screen erstellen. Dafür müssen wir lediglich eine Grafik mit dem Namen splash.png in den Ordner resourcesimages kopieren. Nun ist unsere Anwendung fertig zum Starten: ant run. Das Programm startet (und zeigt einen schönen Splash Screen an) und fordert den Benutzer auf, sich in das System einzuloggen. Der Standardbenutzer und Passwort ist jeweils admin. Auf der linken Seite erscheint die von uns konfigurierte Toolbar (Listing 3) mit den Bereichen Stammdaten, Domänenmodell und Admin und den jeweils zugeordneten Einträgen (Abb. 2). Die einzelnen Domänenobjekte können mit der Maus markiert werden und für jedes Objekt stellt jMatter ein Popup-Menü zur Verfügung, über welches der Benutzer diverse Operationen (Neu anlegen, Suchen etc.) für dieses Objekt ausführen kann.

Abb. 2: Stammdaten, Domänenmodell und Admin

Des Weiteren öffnet sich durch einen Doppelklick auf das Symbol „Autors“ die Übersicht für die Autoren. In dieser Liste kann der Benutzer nach allen Attributen (aufgelistet in der ComboBox) der Autorenklasse suchen. Ein Kern-Feature von jMatter ist die Unterstützung von Multiple Views (die kleinen Icons am oberen rechten Rand), d.h. die Übersicht kann auf unterschiedliche Art dargestellt werden. Über diese Übersicht können nun die CRUD-Operationen für die Domänenobjekte durchgeführt werden. Ein Doppelklick auf einen Autor öffnet einen weiteren Dialog für die Bearbeitung (Abb. 3).

Abb. 3: Bearbeitungsdialog
Query

jMatter bietet ein mächtiges Werkzeug rund um das Thema Query an. Wie in Abbildung 2 ersichtlich, kann der Benutzer auch direkt in der Liste nach Autoren suchen. Der Anwender kann auch seine eigenen Listen definieren und persistieren (vergleichbar mit Datenbank-Views). Die Ergebnisse dieser Query stehen dann immer für das Domänenobjekt zur Verfügung. Abbildung 4. zeigt ein kleines Beispiel, in dem eine Abfrage definiert wird, welche alle Autoren mit dem Job „Software Engineer“ auflistet. Es können natürlich mehrere Attributabfragen in einer Query kombiniert werden. Die Query wird unter den Namen „Software Engineer Autoren“ gespeichert und kann über das Popup-Menü des Domänenobjekts aufgerufen werden. Es wird sofort das Ergebnis als Liste (SmartList) dargestellt. Da jMatter auf Hibernate basiert, können auch direkt HQL-Abfragen definiert und gespeichert werden. Ich kann leider nicht genau auf die einzelnen Details der Abfragen eingehen, und verweise somit auf die Dokumentation von jMatter.

Abb. 4: Abfrage-Definition
Customizing

Eine Frage, die sich immer wieder bei solchen Frameworks stellt, ist die Art und Weise des Customizing. Gerade bei der GUI müssen solche Technologien ein hohes Maß an Freiheit erlauben, denn die generisch erzeugte Oberfläche ist in den wenigsten Fällen zufrieden stellend. Viele Unternehmen haben bereits eine breite Sammlung an GUI-Komponenten, welche in Anwendungen Wiederverwendung finden sollen. jMatter ist in Bezug auf Customizing sehr flexibel und offen. Ganz nach dem Swing-Prinzip gibt es für alle Typen (StringEO, DateEO etc.) definierte Renderer (AtomicRenderer) und Editoren (AtomicEditor). Um eigene Renderer und Editoren zu entwickeln, müssen die Interfaces implementiert, konfiguriert und entsprechend mit den Typen verlinkt werden. Listing 4 zeigt die Default Implementierung von StringEO-Attributen. Wie in Abbildung 3 ersichtlich, werden StringEO Attribute als Textfelder dargestellt.

Listing 4
------------------------------------------------------------------------
  public class StringEditor extends JTextField implements AtomicEditor,
             ActionNotifier
  {
     public StringEditor() { super(12); }

     public void render(AtomicEObject value)
     {
        if (value.field() != null && value.field().displaysize() > 0
              && value.field().displaysize() != getColumns())
        {
           setColumns(value.field().displaysize());
        }

        StringEO eo = (StringEO) value;
        if (!getText().equals(eo.stringValue()))
           setText(eo.stringValue());
     }
     public int bind(AtomicEObject value)
     {
        StringEO eo = (StringEO) value;
        eo.setValue(getText());
        return 0;
     }
  }

Des Weiteren erfolgt hier auch das Binding zwischen der grafischen Komponente und dem Model. Welche Attribute mit welchen Renderern/Editoren dargestellt werden, wird im SwingViewMechanism konfiguriert.

Natürlich können auch benutzerdefinierte Dialoge, Panels, Wizards etc. für die eigenen Applikation entwickelt und eingebunden werden.

Deployment

Nach relativ „kurzer“ Entwicklungszeit haben wir unser System fertig implementiert und möchten dieses dem Kunden zur Verfügung stellen. Hier gibt es viele Varianten, doch eine sehr beliebte, gerade bei Swing Anwendungen, ist das Deployment mit Java Web Start. Hier macht sich vor allem der automatische Update-Mechanismus von Anwendungen bezahlt. Wird eine Anwendung mit Java Web Start gestartet, wird zuerst nach einer neuen Version gesucht und diese bei Bedarf auf dem Clientrechner geladen. jMatter stellt für das Deployment wieder passende Ant Tasks und Templates zur Verfügung. Der Entwickler muss lediglich zwei Konfigurationsdateien an die eigenen Bedürfnisse anpassen. Zum einen gibt es die Datei resources/project.properties, wo die Addresse und das Port der JNLP-Datei angegeben wird. Weitere Projekteigenschaften, wie Herausgeber, Security etc. können noch in der Datei resources/project-jnlp.vm vorgenommen werden. Mit dem Befehl ant jws-dist wird das Deployment gestartet und im Verzeichnis dist wird ein WAR-File erzeugt. Um die Anwendung zu starten, wird dieses WAR-File in einen Web Server kopiert.

Features von jMatter

  • Generische GUI basierend auf dem Domänenmodell
  • Flexible Abfragemöglichkeiten von Daten und Erstellen von Smart Lists
  • Authentifizierung
  • Logging
  • JFreeReport Integration
  • Persitierung mit Hibernate
  • Deployment mit Java Web Start
  • Import/Export von Daten (XML, CSV)
  • Wizard Support
  • Unterstützung von Polymorphismus
  • Customizing von GUI-Elementen.
Fazit

Ich konnte in diesem Artikel leider nicht den auf gesamten Umfang dieser recht impulsiven Technologie eingehen. Der Kasten mit den Features zeigt aber, dass jMatter bereits einen mächtigen Umfang an Funktionalität „out-of-the-box“ bietet und dadurch eine agile Entwicklung von Anwendungen möglich macht. Auch werden bereits grafische Tools für jMatter angeboten, wie das IntellJ Plug-in oder der Design Editor UltraViolet. Mit UltraViolet kann das Domänenmodell grafisch modelliert und anschließend der jMatter Code generiert werden, ganz nach dem Motto Modell-getriebener Entwicklung. Derzeit wird auch an einem grafischen Projekt-Builder für jMatter Applikationen gearbeitet.

Markus Demolsky ist Software-Engineer und Consultant. In seiner selbstständigen Tätigkeit unterstützt er zusammen mit Indoqa andere Unternehmen im Bereich Softwarearchitektur/-design und Open-Source-Technologien im Java-EE-Umfeld. Aktuell arbeitet er gemeinsam mit Dr. Alexander Schatten an einem Buch zum Thema „Software Engineering – Best Practices“.
Geschrieben von
Markus Demolsky
Kommentare

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht.