Modulare Enterprise-OSGi-Anwendungen: Let’s transact!

JTA, JPA und Eclipse Persistence

Leider werden die Probleme noch größer, wenn wir uns die Integration von JTA-Transaktionen mit JPA anschauen. Die Operationen auf den JPA-Entitäten sollen an die JTA-Transaktionen gekoppelt werden. JPA kennt zwei verschiedene Mechanismen zur Steuerung von Transaktionen: RESOURCE_LOCAL und JTA. Bei RESOURCE_LOCAL werden die Transaktionen programmatisch verwaltet, bei JTA über den JEE-Container, also den Application Server. Die Einstellung erfolgt in der persistence.xml. Um Transaktionen gemäß OSGi-Enterprise-Standard zu verwalten, wäre folglich JTA die richtige Wahl. Wird JTA als Mechanismus konfiguriert, hängt sich der EntityManager an die JTA-Transaktionen dran. Genau das wollen wir. Hier macht uns jedoch die von uns gewählte JPA-Implementierung Eclipse Persistence einen Strich durch die Rechnung. Konfigurieren wir bei Eclipse Persistence JTA als Mechanismus zur Steuerung der Transaktionen, verlangt Eclipse Persistence zwingend eine JNDI-Ressource, unter der es die JTA-Transaktion findet. So etwas gibt es aber bei uns gar nicht. Wir haben weder JNDI noch einen Container. Hibernate bietet für solche Fälle die Möglichkeit, eine eigene Klasse anzugeben, um auf den JTA TransactionManager zuzugreifen, diese Klasse wird mit der Property hibernate.transaction.manager_lookup_class gesetzt. Mit Apache Open JPA geht es sogar noch eleganter. OpenJPA kann direkt auf den OSGi Service mit der DataSource zugreifen:

osgi:service/javax.sql.DataSource/(osgi.jndi.service.name=jdbc/TradeDataSource)

In unserem Beispielprojekt sind wir jedoch in einer Sackgasse angelangt. Wir sind gezwungen, entweder eine andere JPA-Implementierung zu verwenden oder auf JTA zu verzichten.

Transaktionen à la Spring

Ob mit oder ohne JTA – den Boilerplate-Code wollen wir beseitigen. Statt des Codes in Listing 1 mit Boilerplate wollen wir Transaktionen wie folgt verwenden:

@Transactional
public  void createEntity(T entity) {
    entityManager.persist(entity);
}

In diesem Listing ist der Boilerplate-Code zum Auf- und Abbau der Transaktion verschwunden, und um Exceptions müssen wir uns auch nicht mehr kümmern. Wir geben nur noch an, dass wir eine Transaktion brauchen, nicht jedoch, wie das passieren soll. Das bezeichnen wir als deklarative Transaktionssteuerung. Deklarative Transaktionen sind der bevorzugte Weg für Spring. Das funktioniert auch für unsere Enterprise-Anwendung, wie wir nun lernen werden.

Für deklarative Transaktionen à la Spring brauchen wir zweierlei: Erstens müssen wir in der Spring-Konfiguration angeben, dass wir Transaktionen über Annotations steuern wollen. Zweitens müssen wir einen Spring TransactionManager konfigurieren, der die Transaktionen verwaltet. Die Spring-Konfiguration für Gemini Blueprint, die genau das tut, zeigt Listing 5.

Listing 5

Mit <tx:annotation-driven/> geben wir an, dass wir Transaktionen über Annotations steuern (hier wird in der Konfiguration der Namespace von Spring tx verwendet). Anschließend konfigurieren wir den TransactionManager für JPA als Instanz der Klasse org.springframework.orm.jpa.JpaTransactionManager. Der TransactionManager erhält noch eine Referenz auf unsere EntityManagerFactory. Das war schon alles. Jetzt haben wir endlich die ersten Transaktionen in unserer Enterprise-Anwendung. Brauchen wir den TransactionManager nicht nur in einem Bundle, können wir ihn als OSGi Service veröffentlichen. Das ist über Gemini Blueprint möglich, wie im vorherigen Artikel beschrieben.

Moment mal, was ist denn mit Exceptions? Tritt eine Exception auf, verwendet Spring eine einfache Strategie: Bei allen RuntimeExceptions wird ein Rollback gemacht, bei checked Exceptions nicht. Dieses Verhalten kann jedoch nahezu beliebig konfiguriert werden, wie der Spring-Dokumentation [9] zu entnehmen. Geht irgendetwas mit der Transaktion schief, verursacht der Transaction Manager eine TransactionException.

Den Boilerplate-Code sind wir nun losgeworden, indem wir Transaktionen deklarativ über Spring steuern. Bis jetzt haben wir uns dabei jedoch auf JPA beschränkt. Spring-Transaktionen können jedoch auch mit JTA kombiniert werden. Dazu mehr im nächsten Abschnitt.

Kommentare

Schreibe einen Kommentar

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