Dynamische Serveranwendungen

Persistenz und JSON APIs

Gunnar Wagenknecht

EclipseRT ist das Top-Level-Projekt bei Eclipse für sämtliche Runtime-relevanten Technologien und Aktivitäten. Im ersten Teil wurde das Top-Level-Projekt samt einer Auswahl seiner Projekte vorgestellt. Dabei entstand die Grundlage für einen eigenen OSGi Stack auf Basis von Equinox und Gyrex. Im zweiten Teil wird dieser Stack schrittweise mit Persistenz von Daten und einem JSON sprechenden Web-API so erweitert, dass eine solide Basis für eigene Serveranwendungen geschaffen wird.

In Teil 1 wurde anhand von Beispielen gezeigt, wie einfach sich ein eigener OSGi Runtime Stack kreieren lässt und wie damit modulare Anwendungen entwickelt werden können. Der zweite Teil baut nahtlos auf diesen Beispiele auf. Die fertig eingerichtete Entwicklungsumgebung mit der EclipseRT Target Platform aus dem ersten Teil wird ohne Änderungen weiter genutzt. Neben Equinox und Gyrex ist dort auch EclipseLink enthalten. Der entwickelte OSGi Service für Grußbotschaften wird um eine weitere Implementierung ergänzt, die die Daten mittels JPA in einer Datenbank ablegt. Zusätzlich werden neue JAX-RS-Ressourcen erstellt, die als REST Services verfügbar gemacht werden und JSON ausgeben und verstehen. Der gesamte Quellcode der Beispiele ist zusammen mit den Quellen des ersten Teils online abrufbar [1].

Artikelserie

  1. Von Null auf REST mit JAX RS
  2. Persistenz und JSON APIs
Persistenz mit JPA in OSGi

JPA ist ein Java-Standard, um Objekte in Datenbanken abbilden zu können. Im EclipseRT-Projekt findet sich mit EclipseLink sogar die Referenzimplementierung für den JPA-Standard wieder. Zusätzlich zu JPA unterstützt EclipseLink schon seit vielen Jahren auch die OSGi-Welt. Zunächst ging das nur auf eine EclipseLink-eigene Weise. Mittlerweile hat aber die OSGi Enterprise Expert Group einen Standard verabschiedet, mit dem aus der OSGi-Welt auf JPA zugegriffen werden kann. Dieser wird im EclipseRT-Gemini-JPA-Projekt implementiert und baut im Wesentlichen auf OSGi Services und Persitence Bundles (dazu später mehr). In den Beispielen wird ausschließlich der standardisierte Ansatz genutzt.

Im ersten Teil wurde ein OSGi Service für Grußbotschaften entwickelt. Sie eignen sich hervorragend als Daten, die mit JPA abgespeichert und gelesen werden können. Allerdings wird die Persistenz nicht in die existierende Implementierung aus dem ersten Teil integriert, sondern es wird eine komplett neue Implementierung des GreetingService erstellt und als weiterer OSGi Service verfügbar gemacht. Dank einer Eigenschaft von OSGi kann diese Implementierung zusammen mit der ersten zur Laufzeit parallel betrieben werden. Der Servicekonsument kann entweder selbst entscheiden, welche Implementierung er nutzen möchte, oder dies der OSGi Service Registry überlassen, die mittels Serviceranking eine bevorzugte Implementierung auswählen wird. Durch ein Property bei der Serviceregistrierung kann das Ranking so beeinflusst werden, dass die JPA-Version bevorzugt wird. Es muss ein neues OSGi-Bundle-Projekt für die JPA-Implementierung angelegt werden. Auch dabei ist wiederum kein Aktivator notwendig, da vollständig mit Declarative Services gearbeitet werden kann.

Um Daten mit JPA persistieren zu können, werden Objekte mit Annotationen versehen. Zusätzlich müssen die annotierten Klassen in einer Persistence Unit (persistence.xml) aufgelistet werden. Diese muss durch einen Meta-Persistence-Eintrag im Bundle Manifest referenziert werden. Das OSGi Bundle samt Persistence Unit und Eintrag im Bundle Manifest wird auch Persistence Bundle genannt. Ein OSGi-JPA-Provider stellt für solch ein Bundle dann einen JPA Entity Manager als OSGi Service bereit. Die Target Platform enthält bereits Gemini JPA, das auf Basis von EclipseLink einen OSGi-JPA-Provider darstellt. Listing 1 skizziert als Grundlage für die Persistenz der Grußbotschaften eine JPA Entity samt der dazugehörigen Persistence Unit und des notwendigen Eintrages im Bundle Manifest.

Listing 1: JPA Entity und Persistence Unit

GreetingEntity.java:
@Entity
@NoSql(dataFormat = DataFormatType.MAPPED)
public class GreetingEntity {
  @Id @GeneratedValue @Column
  private String id;
  @Column
  private long created;
  @Column
  private String text;
  ...//getter and setter
}

META-INF/persistence.xml:
hello.jpa.GreetingEntity

META-INF/MANIFEST.MF:
Manifest-Version: 1.0
Bundle-SymbolicName: hello.jpa
...
Meta-Persistence: META-INF/persistence.xml
Geschrieben von
Gunnar Wagenknecht
Kommentare

Schreibe einen Kommentar

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