Tutorial: Datenbankanbindung mit EclipseLink unter Apache Karaf

23.09.2014

©-t_kimura---istockphoto.com_blogMöchte man eine OSGi Anwendung betreiben, ist dazu erstmal nicht viel nötig: Die gewünschte Implementierung nehmen, eigene Bundles deployen und schon kann es losgehen. Wächst mit der Zeit die eigene Software, steigen aber auch die Anforderungen an die Laufzeitumgebung. Mit Karaf bietet das Apache Projekt eine kompakte Plattform zum Betrieb von OSGi Anwendungen, welche sich durch ein reichhaltiges Plugin-Angebot (sog. Features) erweitern lässt.

 

Basis vieler Anwendungen ist die Anbindung an eine Datenbank. Im Java Umfeld bietet sich dafür der Standard JPA und eine seiner Implementierungen an. Während Apache Karaf in der aktuellen Version (v3.0.1, Stand Juli 2014) Unterstützung für OpenJPA und Hibernate anbietet, muss man für EclipseLink ein paar Umwege gehen. Damit dies gelingt, gibt es hier nun die Schritt-für-Schritt Anleitung dazu. Grundlegende Kenntnisse im Umgang mit OSGi und Blueprint werden vorausgesetzt.

EclipseLink Feature installieren

Zuerst muss das EclipseLink Basispaket installiert werden. Dazu gehören die Karaf-Features „jpa“ und „transaction“, welche die APIs und Blueprint Integration bereitstellen. Für EclipseLink wird die Version 2.4.2 verwendet, die erfahrungsgemäß in dieser Umgebung gut funktioniert. Zusätzlich ist noch der jeweilige Datenbanktreiber erforderlich (im Beispiel Oracle).

feature:install jpa
feature:install transaction
install -s mvn:org.eclipse.persistence/org.eclipse.persistence.antlr/2.4.2
install -s mvn:org.eclipse.persistence/org.eclipse.persistence.asm/2.4.2
install -s mvn:org.eclipse.persistence/org.eclipse.persistence.core/2.4.2
install -s mvn:org.eclipse.persistence/org.eclipse.persistence.jpa/2.4.2
install -s mvn:org.eclipse.persistence/org.eclipse.persistence.jpa.jpql/2.4.2

 

DataSource erstellen

Im nächsten Schritt muss eine DataSource angelegt werden. Dazu gibt es in Karaf mehrere Möglichkeiten, beispielsweise über die Karaf-Konsole. In diesem Beispiel wird ein DataSource-Bundle angelegt. Das ermöglicht eine saubere Konfiguration und die Nutzung des OSGi ConfigurationAdmin Services.
Die Struktur des Bundles ist sehr simpel. Über ein Maven Projekt und das Felix Maven Bundle Plugin lässt sich das Paket mit wenig Aufwand bauen. Wichtig ist die Blueprint-Konfiguration unter /src/main/resources/OSGI-INF/blueprint.xml. Hier wird die DataSource als Bean erstellt und anschließend als OSGi Service bereitgestellt. Bei der Konfiguration hilft der ConfigAdmin. Im Karaf Ordner kann unter dem Verzeichnis /etc/ eine Datei namens  de.doubleslash.sample.datasource.cfg angelegt werden, um die Default-Werte zur Laufzeit zu ändern.

<?xml version="1.0" encoding="UTF-8"?>
   <blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0" xmlns:cm="http://aries.apache.org/blueprint/xmlns/blueprint-cm/v1.1.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.osgi.org/xmlns/blueprint/v1.0.0 http://www.osgi.org/xmlns/blueprint/v1.0.0/blueprint.xsd http://aries.apache.org/blueprint/xmlns/blueprint-cm/v1.1.0 http://svn.apache.org/repos/asf/aries/trunk/blueprint/blueprint-cm/src/main/resources/org/apache/aries/blueprint/compendium/cm/blueprint-cm-1.1.0.xsd">
   <!-- Defines the configuration of the data source -->
   <cm:property-placeholder persistent-id="de.doubleslash.sample.datasource" update-strategy="reload">
      <cm:default-properties>
         <cm:property name="jdbc.url" value="jdbc:oracle:thin:@dbserver:1521:sid" />
         <cm:property name="jdbc.user" value="username" />
         <cm:property name="jdbc.password" value="password" />
         <cm:property name="jdbc.pool.enabled" value="true" />
         <cm:property name="jdbc.pool.minsize" value="5" />
         <cm:property name="jdbc.pool.maxsize" value="10" />
         <cm:property name="jdbc.pool.timeout" value="3000" />
      </cm:default-properties>
   </cm:property-placeholder>
 
   <!-- Defines the data source -->
   <bean id="dataSource" class="oracle.jdbc.pool.OracleDataSource">
      <property name="URL" value="${jdbc.url}" />
      <property name="user" value="${jdbc.user}" />
      <property name="password" value="${jdbc.password}" />
      <property name="connectionCachingEnabled" value="${jdbc.pool.enabled}" />
      <property name="connectionCacheProperties">
         <props>
            <prop key="MinLimit">${jdbc.pool.minsize}</prop>
            <prop key="MaxLimit">${jdbc.pool.maxsize}</prop>
            <prop key="InitialLimit">${jdbc.pool.minsize}</prop>
            <prop key="ConnectionWaitTimeout">${jdbc.pool.timeout}</prop>
         </props>
      </property>
   </bean>
 
   <!-- Publishes the data source as service -->
   <service interface="javax.sql.DataSource" ref="dataSource">
      <service-properties>
         <entry key="osgi.jndi.service.name" value="jdbc/datasource" />
      </service-properties>
   </service>
 
</blueprint>

 

EclipseLink Adapter erstellen

Damit EclipseLink seinen Dienst leistet, braucht es unter Karaf noch ein zusätzliches Adapter-Bundle. Dieses muss aktuell selbst gebaut werden, welches aber dank der Community recht simpel ist.
Unter https://github.com/lburgazzoli/lb-karaf-examples-jpa gibt es eine Beispielimplementierung zur freien Verwendung unter der Apache Lizenz.

Persistenzbundle erstellen

Nun ist es fast geschafft. Wie in jeder JPA Anwendung ist auch hier eine persistence.xml nötig. In dem Bundle, in welchem die JPA Entities liegen, wird unter dem Pfad /src/main/resources/META-INF/persistence.xml folgender Inhalt abgelegt:

<persistence xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd" version="2.0">
   <persistence-unit name="DatabaseApplication" transaction-type="RESOURCE_LOCAL">
      <provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
      <jta-data-source>osgi:service/javax.sql.DataSource/(osgi.jndi.service.name=jdbc/datasource)</jta-data-source>
      <non-jta-data-source>osgi:service/javax.sql.DataSource/(osgi.jndi.service.name=jdbc/datasource)</non-jta-data-source>
      <class>de.doubleslash.sample.dmo.SamplePersistenceDMO</class>
      <exclude-unlisted-classes>false</exclude-unlisted-classes>
      <properties>
         <property name="eclipselink.weaving" value="true" />
         <property name="eclipselink.target-server" value="de.doubleslash.eclipselink.adapter.EclipseLinkOSGiServerPlatform" />
      </properties>
   </persistence-unit>
</persistence>

Zu beachten ist hier, dass unter der Eigenschaft eclipselink.target-server die Plattform-Klasse aus dem Adapter Bundle angegeben ist. Außerdem muss das Weaving aktiviert werden.
Bei Nutzung des Felix Maven Bundle Plugins wird automatisch unter META-INF nach einer persistence.xml gesucht. Sollte diese Datei aus irgendeinem Grund an anderer Stelle liegen, kann man dies mit dem MANIFEST Header Meta-Persistence angeben. Es muss nur sichergestellt sein, dass die Datei sich im Classpath befindet.

Zugriffsbundle erstellen

Nun steht alles bereit, um auf die Datenbank zugreifen zu können. Es gibt zwei Möglichkeiten, JPA zu nutzen:

Manuell

Wenn man lieber den manuellen Weg gehen und die Kontrolle behalten möchte, kann man sich die EntityManagerFactory aus der OSGi Service Registry holen. Dazu muss nur eine ServiceReference mit dem Interface javax.persistence.EntityManagerFactory und dem Filter (osgi.unit.name=DatabaseApplication) abgefragt werden. Anschließend können wie gewohnt EntityManager erzeugt und genutzt werden. Das Transaktionsmanagement erfolgt hier manuell.

Blueprint

Im Gegensatz dazu lässt sich das mit Blueprint sehr elegant automatisieren. Hierfür wird folgende Blueprint Konfiguration benötigt:

<?xml version="1.0" encoding="UTF-8"?>
<blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.osgi.org/xmlns/blueprint/v1.0.0 http://www.osgi.org/xmlns/blueprint/v1.0.0/blueprint.xsd" xmlns:jpa="http://aries.apache.org/xmlns/jpa/v1.0.0" xmlns:tx="http://aries.apache.org/xmlns/transactions/v1.0.0">
   <bean id="DatabaseApplicationDAO" class="de.doubleslash.sample.dao.SampleDAO">
      <jpa:context property="entityManager" unitname="DatabaseApplication" />
      <tx:transaction method="*" value="Required" />
   </bean>
</blueprint>

Blueprint erstellt die DAO Bean und injected den EntityManager, sodass er direkt genutzt werden kann. Das Lifecycle Management wird dem Container überlassen, d.h. der EntityManager darf nach Benutzung nicht manuell geschlossen werden. Das property-Attribut unter jpa:context muss dem Feldnamen bzw. dem Setter für den Entity Manager entsprechen.
Über die Anweisung tx:transaction erzeugt Blueprint bei jedem Datenbankzugriff automatisch eine Transaktion und committed diese am Ende oder sorgt für einen Rollback im Fehlerfall.
Achtung: Voraussetzung für das automatische Management ist, dass der transaction type in der persistence.xml auf JTA geändert wird!

Fazit: Mit wenigen Anpassungen lässt sich EclipseLink auch unter Karaf wunderbar verwenden. In naher Zukunft wird das Karaf Team eine integrierte Unterstützung für EclipseLink anbieten, sodass zumindest der zusätzliche Adapter entfallen sollte.


Quellen:
[1] Bildquelle: iStock © t_kimura

 

doubleSlash-Teaser-Blog_Programmierung

Zurück zur Übersicht

Ein Kommentar zur “Tutorial: Datenbankanbindung mit EclipseLink unter Apache Karaf

  1. In Karaf 4 gibt es jetzt ein eclipselink feature. Damit ist die Integration noch ein wenig einfacher.

    Mit Hilfe von pax-jdbc kann man eine DataSource jetzt auch aus einer reinen config erstellen lassen, auch mit pooling und JTA support.

    Last but not least unterstützen die neuesten Versionen von Aries JPA und transaction nun auch die Standard annotations @PersistenceContext und @Transactional. Es reicht also eine normale bean im xml ohne die speziellen tags.

    Auf meiner Website finden sich einige Beispiele.

Kommentar verfassen

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert

*Pflichtfelder

*