Apache MyFaces Orchestra

JSF und JPA – aber einfach

Mario Ivankovits

Wer eine JSF-Applikation mit Datenbankzugriff erstellt, wird bald merken, dass einige Hürden zu nehmen sind. LazyInitializationExceptions und NonUniqueObjectExceptions treiben den geneigten Entwickler rasch zur Verzweiflung. Mit Bord-Mitteln ist diesen Problemen kaum Herr zu werden. Mithilfe von Spring ist es dem MyFaces-Team gelungen, eine Bibliothek zu erstellen, die durch Einführung neuer JSF-„Scopes“ die neben der von JPA versprochenen Einfachheit im Umgang mit der Datenbank auch JSF-Applikationen zur Verfügung stellt.

Das Problem ist darin zu suchen, dass in JPA-Implementierungen wie TopLink Essentials oder Hibernate jedes geladene Datenbankobjekt vom EntityManager verwaltet und gecached wird. Dafür gibt es gute Gründe. Zum Beispiel soll wiederholtes Lesen desselben Satzes aus der Datenbank auch immer die gleiche Instanz des zugehörigen POJOs liefern. Das erhöht nicht nur die Performance der Applikation, es vereinfacht auch die Programmierung von voneinander unabhängigen Prozessen, die auf dieselbe Datenbasis zugreifen, da man jede Änderung am Datenbankobjekt sofort zu sehen bekommt. Die Instanz des EntityManagers muss also vom Zeitpunkt des Ladens bis zum Abschluss der Arbeit (meistens ein commit) dieselbe sein. Umgekehrt müssen aber auch die im Bean zwischengespeicherten Pojo-Instanzen dieselben sein, die man vom EntityManager beim Laden bekommen hat. Man spricht hier von einer „Unit of work“. Selbst eine einfache Stammdatenwartung erstreckt sich in einer Webapplikation aber über mehrere HTTP-Requests.

Das „Conversation“- Konzept

Da eine Web-Applikation üblicherweise Anfragen des Benutzers beantwortet, spricht man hier auch von conversations. Eine Conversation beginnt zum Beispiel damit, dass die Stammdaten eines Kunden zum Bearbeiten ausgegeben werden und endet damit, dass auf „Speichern“ gedrückt wird. Eine Conversation ist demnach gleichbedeutend der „Unit of work“. JSF ist grundsätzlich nicht sehr hilfreich, wenn es darum geht, in so einem Szenario Daten von einem Request zum nächsten zu bringen. Dazu gibt es in der MyFaces Tomahawk-Bibliothek das saveState-Tag. Da dabei aber die Objekte serialisiert werden, kann es nicht für unseren Einsatz verwendet werden. Es wäre also hilfreich, wenn neben dem Session- und Request Scope auch noch ein Conversation-Scope zur Verfügung stehen würde.

Spring

Das JSF-Managed-Bean-System kann in Bezug auf die verfügbaren Scopes nicht erweitert werden, daher verwendet Apache MyFaces Orchestra als Basis dafür das Spring Framework, außerdem bringt es mit seinen Spring-Templates und -Annotations bereits alles mit, was später notwendig ist, um mit dem EntityManager zu arbeiten. Dabei sei angemerkt, dass Orchestra selbst nicht auf Annotations angewiesen ist und daher auch noch in JDK-1.4-Umgebungen eingesetzt werden kann. Bevor man sich aber mit neuer Freude an die Applikationsentwicklung machen kann, muss man die Hürden der Installation überwinden. Eine ausführliche Dokumentation ist auf der Orchestra-Webseite zu finden.

Orchestra Core

Apache MyFaces Orchestra besteht aus zwei Modulen:

  • core
    Das ist das Basis-System, das ohne Java 5.0-Sprachfeatures auskommt. Enthaltene Funktionen sind der Conversation Scope, der View-Controller und ein URLParameterNavigationHandler.
  • core15
    core 15 sind Erweiterungen zum Basis-System unter Ausnutzung der Java 5.0-Sprachfeatures. Die Funktionen sind Annotations für die Conversation-Verwaltung und den View-Controller sowie eine JSF-DynaForm-Komponente.

In Orchestra wurde großer Wert auf die Erweiterbarkeit gelegt. So ist es zum Beispiel möglich, statt JPA auch direkt Hibernate (ohne JPA-Layer) zu verwenden. Da bei Apache aber keine Abhängigkeit zu einer LGPL/GPL-Software erlaubt ist, soll dazu ein eigenes Projekt gestartet werden.

Beispiel

In einer Apache-MyFaces-Orchestra-Umgebung sollten zur besseren Übersichtlichkeit alle Beans in der Spring-Konfiguration eingetragen werden. Für all jene, die bis jetzt noch nicht Spring verwendet haben, sei gesagt: Man lernt rasch die erweiterten Möglichkeiten zur Bean-Konfiguration zu schätzen. Listing 1 zeigt eine solche Bean-Definition in Spring. Diese Konfiguration macht nichts anderes, als beim ersten Zugriff auf das Bean eine Conversation zu starten und dieser eine Instanz des Beans zuzuordnen. Gleichzeitig wird der Conversation ein EntityManager zugeordnet, um sicherzustellen, dass nachfolgende Zugriffe auf den EntityManager immer die richtige Instanz bekommen.

Listing 1

Der Auszug (Listing 3) aus dem Bean configuratorData ist für die JSF-Action Behandlung zuständig und verwendet DAOs (Listing 2), um auf die Datenbank zuzugreifen. Der EntityManager, der hier via @PersistenceContext-Annotation zugeordnet wird, kommt bereits aus der Conversation, da der Methodenaufruf innerhalb des Contexts des Conversation-Scoped-Beans erfolgt. Zu beachten ist, dass sowohl das configuratorData-Bean als auch das DAO aussehen wie gewohnt, es gibt keine besonderen Programmierrichtlinien zu beachten. Letztlich werden in der buyAction (Listing 3) die Änderungen in die Datenbank geschrieben (@Transaction) und die Conversation beendet.

Listing 2
public class PieceDAO
{
    @PersistenceContext
    private EntityManager entityManager;

    public Piece getByKey(Long pieceId)
    {
        return entityManager.find(Piece.class, pieceId);
    }
}
Listing 3
public String orderItemAction()
{
    if (orderHead == null)
    {
        orderHead = new OrderHead();
    }

    Piece piece = pieceDao.getByKey(getSelectedPiece());

    OrderItem orderItem = new OrderItem();
    orderItem.setPiece(piece);
    orderItem.setAmount(1);

    orderHead.addOrderItem(orderItem);

    return null;
}

@Transactional()
public String buyAction()
{
    orderHeadDao.save(orderHead);

    Conversation.getCurrentInstance()
        .invalidate();

    return "success";
}
Fazit

Im Rahmen dieses Artikels sollte gezeigt werden, dass die Zusammenarbeit mit der Datenbank via JPA im JSF-Umfeld nicht notwendigerweise ein Buch mit sieben Siegeln sein muss. Aufgrund der Verschlossenheit des JCP kann den JSR-299 (Web Beans)- Interessierten nur gesagt werden, dass keine Informationen über den Stand der Entwicklung und den zu erwartenden Ausgang vorhanden sind. Apache MyFaces Orchestra aber bietet einen einfachen Weg, auch bestehende Applikationen zu erweitern und trägt somit der evolutionären Entwicklung von Applikationen Rechnung.

Mario Ivankovits ist Programmierer bei der Firma OPS EDV VertriebsgesmbH. Seit etwa vier Jahren ist er in der Open Source Community aktiv, im Speziellen ist er Committer und Mitglied des Project Management Committees bei den Projekten Apache Commons und Apache MyFaces.
Geschrieben von
Mario Ivankovits
Kommentare

Schreibe einen Kommentar

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